Skip to content
Liquidify
HomeDocsComponentsExamplesPlayground
⌘K
(opens in new tab)
Liquidify

Accessible React controls with a CSS and SVG material engine.

Product

ComponentsExamplesPlaygroundPackages

Learn

DocumentationGetting startedConceptsAI resources

Project

CommunityShowcaseVersionsGitHub

Independent open-source software. Not affiliated with or endorsed by Apple Inc.

LicenseBrand

Component catalog

Browse the public controls by interaction purpose. Every result links to generated API facts, accessibility behavior, source, and exhaustive stories.

Link

A control that opens a URL — the SwiftUI Link .

import { Link } from "@liquidify/react/link"

Overview

Basic Link

A focused starting point showing Link with its essential configuration.

API

PropTypeDefaultDescription
aria-labelstring | undefined—Accessible name override — required when {@link LinkCommonProps.children} is icon-only.
childrenReactNode—The visible content and accessible-name source — SwiftUI `Link(_ title:, destination:)` (a string title) or the `Link(destination:)` label-closure form (an arbitrary node). An icon-only glass trigger (no visible text, only `leadingIcon` / `trailingIcon`) **requires** an explicit {@link LinkCommonProps. "aria-label" | aria-label} (WCAG 2.1 SC 1.1.1). children role: `label` (token parity — Link's text renders through Button; no `labelProps` seam, per ADR-0028 rule 3 / charter §2 rule 5).
classNamestring | undefined—Optional additional CSS class merged into the glass surface class. The supported per-instance customisation seam: override any `--lq-*` custom property from this class's CSS — the token cascade the engine reads (ADR-0004). No raw inline style is involved, so this stays ADR-0003 clean.
disabledboolean | undefined—Disables the control. Shape N (action `<button>`): native `disabled` + `data-disabled`, no `aria-disabled`. Shape A (any `<a>` mode — inline, or a glass variant with `href`): `aria-disabled="true"` + `data-disabled` + hard suppression (navigation prevented, `onClick` / `onPress` suppressed, hover / press motion suppressed via `[data-disabled] { pointer-events: none }`) — the element **stays focusable** so assistive tech can perceive it (`docs/api-conventions.md` §3).
hrefstring | undefined—The destination URL — SwiftUI `Link(destination:)`. Rendered as the anchor's native `href`. Absent in action mode — an action has no destination.
leadingIconReactNode—Leading glyph rendered before the label. **Glass variants only.**
onClick((event: MouseEvent<HTMLAnchorElement>) => void) | ((event: MouseEvent<HTMLButtonElement>) => void) | undefined—Low-level native passthrough; prefer `onPress`. Fires FIRST, before `onPress` — call `event.preventDefault()` here to suppress `onPress` and the default navigation (charter §1 rules 2–3). Low-level native passthrough; prefer `onPress`. Fires FIRST, before `onPress` — call `event.preventDefault()` here to suppress `onPress` (charter §1 rules 2–3).
onPress(() => void) | undefined—Semantic activation — the SwiftUI `Button(action:)` / environment `openURL` closure Link's action opens `destination` through. Payload-free, fires at most once per interaction, and only AFTER the {@link onClick } escape hatch on any surface where it fired without cancelling (charter §1 rules 1–3). Disabled emits nothing on every surface (audit §8).
ref((instance: HTMLButtonElement | null) => void | (() => VoidOrUndefinedOnly) | DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | RefObject<HTMLButtonElement | null> | ((instance: HTMLAnchorElement | null) => void | (() => VoidOrUndefinedOnly) | DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | RefObject<HTMLAnchorElement | null> | null | undefined—Forwarded ref to the rendered element — the component's native root (or the merged child element on a component that opts into {@link SlottableProps}). Generic over `E` (charter `docs/api-conventions.md` §4 rule 1, default `HTMLElement`) so a component with a polymorphic root (Link's navigation / action mode union, Text's `as`) can instantiate the concrete element per variant instead of leaving every consumer with a widened `Ref<HTMLElement>`. A component that does not narrow simply inherits the `HTMLElement` default — source-compatible with every pre-existing non-generic `extends ControlProps`.
sizeButtonSize | undefinedButton's own default (`"regular"`).Control size — the `small · regular · large` subset, forwarded to {@link Button}. **Glass variants only**; ignored on the `"inline"` surface, which inherits the surrounding text size. Narrows the inherited {@link SizedControlProps} `size` axis to the three sizes the glass surface ships — the truthful `ButtonSize` re-export (charter §7 rule 4, the composition-wrapper exception: Link may not mint its own `Extract`). Control size — the `small · regular · large` subset, forwarded to {@link Button}. Narrows the inherited {@link SizedControlProps} `size` axis to the three sizes the glass surface ships — the truthful `ButtonSize` re-export (charter §7 rule 4).
targetLinkTarget | undefinedsame-tab (no `target` attribute)New-tab vs same-tab navigation (web-only; SwiftUI's `openURL` has no "new window" concept). `"_blank"` opens a new browsing context, auto-adds `rel="noopener noreferrer"` (never independently settable), and appends a visually-hidden `" (opens in new tab)"` suffix to the accessible name. Absent in action mode — `target` is an anchor-only axis.
tintLiquidTintValue | undefined—System-accent of the control — drawn from the RESTRICTED {@link LIQUID_COLORS} palette (the thirteen Apple system colours). **Orthogonal to a component's `variant`**: it recolours the accent the surface draws from (focus ring, tinted fill, selection) without changing its variant. Resolved via `data-tint` attribute selectors in CSS (tokens-only, ADR-0003).
trailingIconReactNode—Trailing glyph rendered after the label. **Glass variants only.**
variantLinkVariant | undefinedinlineThe surface — SwiftUI `buttonStyle`. `"inline"` (default) is the Text-like inline link; the glass variants render the composed {@link Button}'s surface. Orthogonal to the root element, which follows the `href` discriminant (an `<a>` to navigate, a `<button>` to act).

Guidelines

Do
  • Use Link when its semantics match the content or action.
  • Keep labels concise, specific, and consistent with the surrounding interface.
  • Test the component with keyboard navigation, zoom, and both color schemes.
Don't
  • Do not use Link as a visual substitute for a different semantic element.
  • Do not rely on color or an icon alone to communicate essential meaning.
  • Do not override the component tokens with fixed values unless the product theme requires it.

Accessibility

Link supports the documented keyboard interactions below.

Keyboard
  • Press Tab to move focus to the control.
  • Use the control's documented activation keys without trapping focus.
  • Provide an accessible name whenever the visible label is absent.

Tokens

NameValue
--lq-color-accent#007aff
--lq-color-action-primary#007aff
--lq-duration-fast120ms
--lq-easing-standardcubic-bezier(0.25, 0.1, 0.25, 1)
--lq-focus-ring-colorvar(--lq-button-ring, var(--lq-color-accent))var(--lq-toggle-ring, var(--lq-color-accent))var(--lq-slider-ring, var(--lq-color-accent))var(--lq-tint-current, var(--lq-color-accent))
--lq-font-size-0.625rem0.6875rem0.75rem0.8125rem0.9375rem1.0625rem1.375rem1.625rem
--lq-glass-440.71.15var(--lq-segmented-control-indicator-blur)calc(var(--lq-glass-material-blur) * 8)var(--lq-shadow-presentational)
--lq-glass-fill-0Resolved by the active Liquidify theme
--lq-hit-target-2.75rem
--lq-motion-1.0250.9500ms1.15
--lq-opacity-disabled0.6
--lq-radiusComponent-defined value
--lq-radius-pill9999rem
--lq-space-0.0625rem0.125rem0.25rem0.5rem0.75rem1rem1.25rem1.5rem2rem2.5rem3rem3.5rem
--lq-space-20.125rem
--lq-tint-currentvar(--lq-color-accent)light-dark( var(--lq-color-system-blue-default-light, var(--lq-color-accent)), var(--lq-color-system-blue-default-dark, var(--lq-color-accent)) )light-dark( var(--lq-color-system-brown-default-light, var(--lq-color-accent)), var(--lq-color-system-brown-default-dark, var(--lq-color-accent)) )light-dark( var(--lq-color-system-cyan-default-light, var(--lq-color-accent)), var(--lq-color-system-cyan-default-dark, var(--lq-color-accent)) )light-dark( var(--lq-color-system-green-default-light, var(--lq-color-accent)), var(--lq-color-system-green-default-dark, var(--lq-color-accent)) )light-dark( var(--lq-color-system-indigo-default-light, var(--lq-color-accent)), var(--lq-color-system-indigo-default-dark, var(--lq-color-accent)) )light-dark( var(--lq-color-system-mint-default-light, var(--lq-color-accent)), var(--lq-color-system-mint-default-dark, var(--lq-color-accent)) )light-dark( var(--lq-color-system-orange-default-light, var(--lq-color-accent)), var(--lq-color-system-orange-default-dark, var(--lq-color-accent)) )light-dark( var(--lq-color-system-pink-default-light, var(--lq-color-accent)), var(--lq-color-system-pink-default-dark, var(--lq-color-accent)) )light-dark( var(--lq-color-system-purple-default-light, var(--lq-color-accent)), var(--lq-color-system-purple-default-dark, var(--lq-color-accent)) )light-dark( var(--lq-color-system-red-default-light, var(--lq-color-accent)), var(--lq-color-system-red-default-dark, var(--lq-color-accent)) )light-dark( var(--lq-color-system-teal-default-light, var(--lq-color-accent)), var(--lq-color-system-teal-default-dark, var(--lq-color-accent)) )

Key features

  • Liquid material

    Uses Liquidify surfaces and theme-aware design tokens.

  • Typed API

    Provides a typed React API with generated prop documentation.

  • Accessible by default

    Preserves semantic structure, focus visibility, and assistive-technology state.

Resources

  • Source
  • Markdown
  • JSON
  • Storybook
Components