Link
Navigates to another page, screen, or location. Always underlined, always a real link, so the destination is exposed to assistive technology and to the platform.
Basic usage
Install the package:
pnpm add @design-schema/react @design-schema/tokens Import the stylesheet once for the app, then the component:
import '@design-schema/tokens/calm-precise/css';
import '@design-schema/react/index.css';
import { Link } from '@design-schema/react'; Examples
import { Link } from '@design-schema/react';
<Link href="/billing/history" label="View the billing history" />Props
6 rows| Prop | Type | Default | Description |
|---|---|---|---|
| href required | string | — | The destination. A URL on web; a URL or app route on native, resolved by `onPress` when the consumer provides it. |
| label required | string | — | The link text. Also the accessible name. Says where the link goes, not "click here". |
| external | boolean | false | Opens the destination in a new tab or the system browser and appends `copy.externalSuffix` to the accessible name, with a decorative trailing icon. Accessibility: Users are told the link leaves the current context before they activate it (WCAG 3.2.5 advisory, G201). |
| tone | default | inherit | default | `default` uses the link colors. `inherit` takes the surrounding text color and relies on the underline alone — for links inside muted or on-action text. Under `inherit` the color, colorHover and colorVisited bindings are not applied: rest, hover, visited and (on native) pressed all resolve to the inherited color (currentColor on web and Lit, the enclosing TextStyleContext color on native), and the underline and the external icon follow that same color, so an inherited link has no hover or visited color change by design. On web the root takes `color: inherit`, and the color, :visited and :hover rules are scoped to the `tone: default` modifier. On native Link sets no textDecorationColor under either tone (the underline takes the Text color, so it follows the animated label colour), and under `inherit` the label runs no press animation, since rest and pressed resolve to the same colour; a standalone inherit link outside any system Text has nothing to inherit, so its label and icon both use color.foreground. |
| download | boolean | false | Downloads the resource instead of navigating, under the server's file name (a custom file name is out of scope). Web only. |
| current | boolean | false | The link points at the page the user is on, in a navigation list (a SidePanel drawer, a Tree of href nodes): `aria-current="page"` on the anchor on web and Lit, `accessibilityState.selected` on React Native (with the `aria-current="page"` mirror on react-native-web, which drops accessibilityState), `.isSelected` on SwiftUI. The link stays a link and keeps its colours and underline; how a navigation also marks it visually is that container's to say. False writes nothing, so an `aria-current` a consumer passes through `...rest` on web (a `step` or `location`) still applies; while `current` is true the prop wins. Accessibility: The current page is announced, not shown by position or colour alone (WCAG 1.3.1, 4.1.2). |
Events
1 row| Event | Type | Description |
|---|---|---|
| onPress | onClick / click / onPress / action | Fired when the link is activated. On web the default navigation still happens unless the consumer prevents it; on native the consumer must navigate (the system opens URLs with Linking when no handler is given). On Lit the name is the native anchor's own `click`, retargeted out of the shadow root — Link emits no `press` CustomEvent. Cancelling: on web the handler receives the click event and cancels navigation with preventDefault or by returning `false` (typed `(event) => void | boolean`; Link calls preventDefault on `false`); on Lit the consumer calls preventDefault on the click; on native the handler receives `href` and returning `false` cancels the Linking hand-off, the only default action native has. `fires: [user]` means Link never dispatches it itself; on web and Lit a script calling `.click()` on the anchor still fires it, as on any link, and Link does not try to filter that out. |
Accessibility
Decisions this component leaves to you
Supply an accessible name. This component has no text of its own to fall back on, so without one a screen reader announces its role and nothing else.
Implicit ARIA role: link.
Anatomy
What generation guarantees
Accessible name — Every instance carries a programmatic name. Where the component has no text of its own to use, the name is a prop the consumer supplies.
Visible focus — Keyboard focus is always drawn, from the theme’s focus tokens, and is never removed.
Keyboard operable — Everything the pointer can do here, the keyboard can do — see the keyboard section.
Contrast — Text and meaningful non-text contrast meets WCAG AA; the pairs are listed below.
This component does not animate, so it has no reduced-motion behaviour to describe.