@fiscozen/link
v1.0.0
Published
Design System Link component
Keywords
Readme
@fiscozen/link
Flexible link component supporting internal routing (vue-router) and external navigation. Automatically renders as router-link for internal routes, anchor tag for external URLs, or non-interactive span when disabled.
Features
- Internal Routing: Uses vue-router for SPA navigation with RouteLocationRaw support (string or object)
- External Navigation: Supports external URLs with anchor tags
- Disabled State: Renders as non-interactive span with disabled styling
- Multiple Variants: Default and danger types
- Text Styles: Default (underline on hover) or always underlined
- Size Options: sm, md
- TypeScript Type Safety: Discriminated union types enforce correct prop combinations
- Full Accessibility: ARIA support and keyboard navigation
- Security: Automatic rel="noopener noreferrer" for external links with target="_blank"
Installation
npm install @fiscozen/linkBasic Usage
Internal Route (String Path)
<script setup lang="ts">
import { FzLink } from '@fiscozen/link'
</script>
<template>
<FzLink to="/dashboard" size="md">Go to Dashboard</FzLink>
</template>Internal Route (Object with Name)
<template>
<FzLink :to="{ name: 'user', params: { id: 123 }}">
User Profile
</FzLink>
</template>Internal Route (Object with Path and Query)
<template>
<FzLink :to="{ path: '/search', query: { q: 'vue' }}">
Search Results
</FzLink>
</template>External Link
<template>
<FzLink to="https://example.com" external target="_blank">
External Site
</FzLink>
</template>Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| to | RouteLocationRaw \| string | - | Destination route or URL. Type depends on external prop: Internal (external=false or undefined): Accepts vue-router RouteLocationRaw (string path or object with name/path, params, query, etc.). External (external=true): Must be a string URL. |
| type | 'default' \| 'danger' | 'default' | Visual variant indicating link purpose. Affects color scheme. |
| linkStyle | 'default' \| 'underline' | 'default' | Text decoration style. 'default' shows underline on hover, 'underline' always shows underline. |
| size | 'sm' \| 'md' | 'md' | Text size affecting font size and line height. |
| disabled | boolean | false | Disables the link, rendering as non-interactive span with disabled styling. |
| target | string | - | Target attribute for anchor tag (e.g., '_blank', '_self'). Can be used with both internal (router-link) and external links. |
| external | boolean | false | When true, renders as anchor tag with href instead of router-link. Use for external URLs or when router navigation is not desired. |
| replace | boolean | false | Uses router.replace instead of router.push for navigation. Only applies to internal routes (when external is false). |
TypeScript Type Safety
The component uses discriminated union types to enforce correct prop combinations:
Internal links (
external=falseorundefined):toacceptsRouteLocationRaw(string path or object with name/path, params, query, etc.)replacecan be usedtargetcan be used (opens internal route in new tab/window)
External links (
external=true):tomust be a string URLtargetcan be usedreplacecannot be used (not applicable for external links)
TypeScript will show errors if you try to use incompatible prop combinations.
Examples
Navigation Menu
<template>
<nav>
<FzLink to="/dashboard" size="md">Dashboard</FzLink>
<FzLink to="/settings" size="md">Settings</FzLink>
<FzLink :to="{ name: 'profile', params: { id: userId }}" size="md">
Profile
</FzLink>
</nav>
</template>External Links with Security
<template>
<FzLink to="https://example.com" external target="_blank">
Visit Example Site
</FzLink>
</template>The component automatically adds rel="noopener noreferrer" for security when target="_blank" is used.
Disabled State
<template>
<FzLink to="/premium" disabled>
Premium Feature (Requires Upgrade)
</FzLink>
</template>Danger Link
<template>
<FzLink to="/delete-account" type="danger" size="md">
Delete Account
</FzLink>
</template>Replace Navigation
<template>
<FzLink to="/redirect" replace>
Redirect Without History
</FzLink>
</template>Accessibility
FzLink is fully accessible and meets WCAG 2.1 AA standards:
- Keyboard Navigation: All links are keyboard accessible (Tab, Enter)
- Screen Readers: Proper ARIA attributes for disabled state
- Focus Indicators: Visible focus outline with proper contrast
- Semantic HTML: Uses router-link for internal routes, anchor for external
- Disabled State: Renders as span with aria-disabled, role="link", and aria-label
ARIA Attributes
aria-disabled: Set to "true" when link is disabled (string value for Vue 3 compatibility)role: Set to "link" for disabled span to maintain semantic meaningaria-label: Provides accessible label for disabled linksrel: Automatically adds "noopener noreferrer" for external links with target="_blank"
Security
External links with target="_blank" automatically include rel="noopener noreferrer" to:
- Prevent security vulnerabilities (window.opener access)
- Improve privacy (no referrer information sent)
Related Components
- FzNavlink: Navigation link with active state support
- FzButton: Button component for actions
- FzRouterNavlink: Router-aware navigation link
