FairGarden Design

Link

A semantic anchor in six builds: inline links in running text, standalone module links, navigation, stretched titles and note references.

import { Link } from '@fairgarden-private/design/components/Link'

Links carry --primary12 text; the inline underline is the scope's --role-accent at 1.5 px. render swaps the element, for example render={<NextLink href="/trails" />}; these docs render every internal link that way.

Kinds

Kinds

inline (the default) underlines in running text. standalone is the caps module link with a trailing chevron. nav has no rest underline and marks the current page with aria-current="page" or data-active; on hover, bare navigation text (a bar item, a page number, a toolbar link) takes the accent underline. Add list for a link in a list (a navigation panel, footer or drawer): its hover changes only the ink, to --role-link-hover, and adds an underline only where that ink is the main ink. muted rests in --role-muted, as a breadcrumb's ancestors, with the same ink-only hover. external adds the arrow-open mark and "(external site)" for assistive technology.

LinkKinds.tsx
import { Link } from '@fairgarden-private/design/components/Link'
import styles from './kinds.module.css'

export function LinkKinds() {
  return (
    <div className={styles.stack}>
      <p className={styles.text}>
        Read the <Link href="#kinds">trail conditions</Link> before you set out.
      </p>
      <Link kind="standalone" href="#kinds">
        See all trails
      </Link>
      <nav className={styles.nav} aria-label="Example navigation">
        <Link kind="nav" href="#kinds" data-active="">
          Trails
        </Link>
        <Link kind="nav" href="#kinds">
          Maps
        </Link>
        <Link kind="nav" href="#kinds">
          Events
        </Link>
      </nav>
      <ul className={styles.list} aria-label="Example list links">
        <li>
          <Link kind="nav" list href="#kinds">
            Trail maps
          </Link>
        </li>
        <li>
          <Link kind="nav" list href="#kinds">
            Volunteer days
          </Link>
        </li>
      </ul>
      <nav className={styles.nav} aria-label="Example muted links">
        <Link kind="nav" muted href="#kinds">
          Guides
        </Link>
        <Link kind="nav" muted href="#kinds">
          Trail care
        </Link>
      </nav>
      <p className={styles.text}>
        Elevation data from the{' '}
        <Link href="https://www.usgs.gov" external>
          USGS
        </Link>
        .
      </p>
    </div>
  )
}

Primary and secondary

Primary and secondary

Without props a link inherits its scope's scales. secondary recolors the accent underline; primary recolors the text ink and focus ring.

LinkColor.tsx
import { Link } from '@fairgarden-private/design/components/Link'
import styles from './color.module.css'

/** The underline is the secondary's accent; the text stays the primary's step 12. */
export function LinkColor() {
  return (
    <div className={styles.stack}>
      <p className={styles.text}>
        Scope defaults: <Link href="#color">olive × green</Link>
      </p>
      <p className={styles.text}>
        <Link href="#color" secondary="indigo">
          secondary=&quot;indigo&quot;
        </Link>
      </p>
      <p className={styles.text}>
        <Link href="#color" primary="plum" secondary="pink">
          primary=&quot;plum&quot; secondary=&quot;pink&quot;
        </Link>
      </p>
    </div>
  )
}

On grounds

On paper, forest and leaf

The accent follows the ground: a non-text green on paper, a text-safe amber on forest, and the single ink on leaf.

LinkGrounds.tsx
import { PresetGround } from '@/components/PresetGround'
import { Link } from '@fairgarden-private/design/components/Link'
import styles from './grounds.module.css'

const presets = ['paper', 'forest', 'leaf'] as const

export function LinkGrounds() {
  return (
    <div className={styles.row}>
      {presets.map((preset) => (
        <PresetGround key={preset} preset={preset} className={styles.face}>
          <p className={styles.text}>
            On {preset}, <Link href="#grounds">find a preserve</Link> near you.
          </p>
          <Link kind="standalone" href="#grounds">
            See all preserves
          </Link>
        </PresetGround>
      ))}
    </div>
  )
}

API Reference

A semantic anchor. render swaps the element, for example render={<NextLink href="/trails" />}.

  • kind="inline" (default): --role-accent underline in running text.
  • kind="standalone": caps module link with a trailing ›.
  • kind="nav": no rest underline; hover the bare-text underline; current via aria-current="page" or data-active.
  • kind="title": stretched card or list-item title link [D157].
  • kind="noteref" / kind="backref": note call and ↩ return, never underlined.
  • index: the screen-only visited ✓ for long indexes [D174, D175].
  • external: the arrow-open mark plus “(external site)” for assistive technology.
  • list: with nav, the list link’s color-only hover (nav panels, footers, drawers).
  • muted: the --role-muted ancestor ink with a color-only hover (breadcrumbs).
PropTypeDescription
external
boolean | null | undefined

Adds the arrow-open mark and “(external site)” for assistive technology. Default false.

index
boolean | null | undefined

Adds the screen-only visited ✓ used in long indexes, such as reference and archive lists. Default false [D174, D175].

kind
| 'nav'
| 'title'
| 'inline'
| 'standalone'
| 'backref'
| 'noteref'
| null
| undefined

Which build: inline (default) underlines in running text; standalone is the caps module link with a trailing ›; nav has no rest underline and marks the current page; title stretches over a card or list item; noteref and backref are the note call and return (§9.3).

list
boolean | null | undefined

With kind="nav": a list link (nav-panel, footer, drawer and breadcrumb lists), whose hover is --role-link-hover color only, plus the --ds-stroke-1-5 --role-accent underline where that ink is --primary12. Without it, nav is bare navigation text (bar and utility items, page numbers, toolbar links), whose hover is the --border-size-2 --role-accent underline (§9.3) [D181]. Default false.

muted
boolean | null | undefined

Rests in --role-muted instead of --primary12, as a breadcrumb’s ancestors. Hover takes --role-link-hover only (the underline is added where that ink is --primary12); with kind="nav" it replaces the bar item’s bare-text underline (§9.3, §9.8) [D181]. Default false.

primary
| 'ruby'
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| null
| undefined

Primary Radix scale: the link text and focus ring. Never defaulted; omitted, it inherits the scope [D133].

secondary
| 'ruby'
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| 'amber'
| 'blue'
| 'cyan'
| 'grass'
| 'green'
| 'jade'
| 'lime'
| 'mint'
| 'orange'
| 'sky'
| 'teal'
| 'yellow'
| null
| undefined

Secondary Radix scale: the accent underline. Never defaulted; omitted, it inherits the scope.

className
string | undefined

Extra class names, added after the module’s own.

link
LinkKind
type LinkKind = 'nav' | 'title' | 'inline' | 'standalone' | 'backref' | 'noteref'<
  'nav' | 'title' | 'inline' | 'standalone' | 'backref' | 'noteref' | null | undefined
>
LinkProps

Props for Link: anchor props, render, and the kind, mark and color axes.

type LinkProps = {
  /**
   * Which build: `inline` (default) underlines in running text; `standalone`
   * is the caps module link with a trailing ›; `nav` has no rest underline
   * and marks the current page; `title` stretches over a card or list item;
   * `noteref` and `backref` are the note call and return (§9.3).
   */
  kind?: 'nav' | 'title' | 'inline' | 'standalone' | 'backref' | 'noteref' | null;
  /**
   * Adds the screen-only visited ✓ used in long indexes, such as reference
   * and archive lists. Default `false` [D174, D175].
   */
  index?: boolean | null;
  /**
   * Adds the arrow-open mark and "(external site)" for assistive technology.
   * Default `false`.
   */
  external?: boolean | null;
  /**
   * With `kind="nav"`: a list link (nav-panel, footer, drawer and breadcrumb
   * lists), whose hover is `--role-link-hover` color only, plus the
   * `--ds-stroke-1-5` `--role-accent` underline where that ink is
   * `--primary12`. Without it, `nav` is bare navigation text (bar and
   * utility items, page numbers, toolbar links), whose hover is the
   * `--border-size-2` `--role-accent` underline (§9.3) [D181]. Default
   * `false`.
   */
  list?: boolean | null;
  /**
   * Rests in `--role-muted` instead of `--primary12`, as a breadcrumb's
   * ancestors. Hover takes `--role-link-hover` only (the underline is added
   * where that ink is `--primary12`); with `kind="nav"` it replaces the bar
   * item's bare-text underline (§9.3, §9.8) [D181]. Default `false`.
   */
  muted?: boolean | null;
  /**
   * Primary Radix scale: the link text and focus ring. Never defaulted;
   * omitted, it inherits the scope [D133].
   */
  primary?:
    | 'ruby'
    | 'olive'
    | 'sage'
    | 'slate'
    | 'sand'
    | 'gray'
    | 'mauve'
    | 'brown'
    | 'bronze'
    | 'gold'
    | 'red'
    | 'crimson'
    | 'tomato'
    | 'pink'
    | 'plum'
    | 'indigo'
    | 'iris'
    | 'violet'
    | 'purple'
    | null;
  /**
   * Secondary Radix scale: the accent underline. Never defaulted; omitted,
   * it inherits the scope.
   */
  secondary?:
    | 'ruby'
    | 'olive'
    | 'sage'
    | 'slate'
    | 'sand'
    | 'gray'
    | 'mauve'
    | 'brown'
    | 'bronze'
    | 'gold'
    | 'red'
    | 'crimson'
    | 'tomato'
    | 'pink'
    | 'plum'
    | 'indigo'
    | 'iris'
    | 'violet'
    | 'purple'
    | 'amber'
    | 'blue'
    | 'cyan'
    | 'grass'
    | 'green'
    | 'jade'
    | 'lime'
    | 'mint'
    | 'orange'
    | 'sky'
    | 'teal'
    | 'yellow'
    | null;
  /** Extra class names, added after the module's own. */
  className?: string;
}
LinkVariants
type LinkVariants = {
  primary?:
    | 'ruby'
    | 'olive'
    | 'sage'
    | 'slate'
    | 'sand'
    | 'gray'
    | 'mauve'
    | 'brown'
    | 'bronze'
    | 'gold'
    | 'red'
    | 'crimson'
    | 'tomato'
    | 'pink'
    | 'plum'
    | 'indigo'
    | 'iris'
    | 'violet'
    | 'purple'
    | null;
  secondary?:
    | 'ruby'
    | 'olive'
    | 'sage'
    | 'slate'
    | 'sand'
    | 'gray'
    | 'mauve'
    | 'brown'
    | 'bronze'
    | 'gold'
    | 'red'
    | 'crimson'
    | 'tomato'
    | 'pink'
    | 'plum'
    | 'indigo'
    | 'iris'
    | 'violet'
    | 'purple'
    | 'amber'
    | 'blue'
    | 'cyan'
    | 'grass'
    | 'green'
    | 'jade'
    | 'lime'
    | 'mint'
    | 'orange'
    | 'sky'
    | 'teal'
    | 'yellow'
    | null;
  kind?: 'nav' | 'title' | 'inline' | 'standalone' | 'backref' | 'noteref' | null;
  index?: boolean | null;
  external?: boolean | null;
  list?: boolean | null;
  muted?: boolean | null;
}

Specification: DESIGN-SYSTEM.md §9.3 (link) and §3.12 (links in running text).