Skip to content

ActionsLink

Link

The fundamental navigation component. Always uses the native anchor element. Three tones, three sizes, an external variant.

Native <a>3 tonesExternal variant

Demo

The default tone underlines on hover. The muted tone is for navigation chrome. The subtle tone is for in-prose links.

External links

External links get an ExternalLink icon and rel="noopener noreferrer" by default.

External

Sizes

Sizes

Implementation

link.tsx
import Link from "next/link"
import { ExternalLink } from "lucide-react"
import SiteIcon from "@/components/site-icon"

type Tone = "default" | "muted" | "subtle"
type Size = "sm" | "md" | "lg"

interface DocLinkProps {
  href: string
  external?: boolean
  tone?: Tone
  size?: Size
  children: React.ReactNode
}

export function DocLink({ href, external, tone = "default", size = "md", children }: DocLinkProps) {
  const className = `ds-link ds-link--${tone} ds-link--${size}`
  if (external) {
    return (
      <a href={href} target="_blank" rel="noopener noreferrer" className={className}>
        {children}
        <SiteIcon icon={ExternalLink} size="xs" />
      </a>
    )
  }
  return <Link href={href} className={className}>{children}</Link>
}

Props

PropTypeDefaultDescription
hrefstringNoneThe URL
externalbooleanfalseOpens in a new tab; gets an icon and rel=noopener
size"sm" | "md" | "lg""md"Text size
tone"default" | "muted" | "subtle""default"Color treatment

Accessibility

  • Native <a> elements only. No <span onClick>.
  • External links get rel="noopener noreferrer" automatically.
  • Links have a 4 px tap extension on mobile (invisible to the eye, generous to the thumb).
  • Underline is always visible on hover; visible by default for the default tone, hidden by default for the subtle tone (revealed on hover).