System Patterns Docs
    Esc

    Start

    • Overview
    • AI agents
    • Roadmap

    Foundations

    • Brand
    • Color
    • Typography
    • Spacing
    • Layout primitives
    • Radius
    • Borders
    • Elevation
    • Iconography
    • Breakpoints
    • Containers
    • Grid

    Components

    • Accordion
    • Alert
    • Avatar
    • Badge
    • Banner
    • Breadcrumbs
    • Buttons
    • Card
    • Checkbox
    • Chip
    • Code
    • Code block
    • Command menu
    • Date navigator
    • Dialog
    • Divider
    • Empty state
    • Form field
    • Input field
    • Link
    • Loading dots
    • Menu
    • Message
    • Metric
    • Pagination
    • Progress
    • Radio
    • Segmented control
    • Select
    • Sheet
    • Sidebar nav
    • Skeleton
    • Slider
    • Spinner
    • Table
    • Tabs
    • Textarea
    • Toast
    • Toggle
    • Tooltip
    • Topbar

    Data visualization

    • Data visualization
    • Area
    • Bar charts
    • Donut
    • Line
    • Scatter

    Patterns

    • App shell
    • Dashboard
    • Settings
    • Login
    • Form
    • Conversation

    Docs

    • Overview
    • Architecture
    • Contracts
    • Validation

    Link

    Inline navigation inside prose — text that takes you somewhere. The boundary against Button is a test, not a feeling: if the destination could be opened in a new tab, it is a link; if it performs an action instead of moving you, it is a Button wearing link styling, and middle-click, copy-link, and the browser's own status bar all quietly stop working.

    A link carries no scale of its own. It inherits the size, weight, and line height of the prose around it — that is what makes it a link rather than a control — so it has no variant or size axes, only states.

    States

    The underline is the affordance and is present at rest, always. Link inherits the surrounding foreground, so it stays dark on a light surface, light on a dark one, and hue-matched on a paired color surface. Its underline uses that same currentColor at 45% presence, then rises to full strength on hover with no ink, weight, or metric change.

    ExampleStateDriverRolesUsage
    Read the contractRest—inherit · currentColor 45%The parent owns the contrast pair; the underline keeps its hue at lower presence
    Read the contractHover:hovercurrentColorThe underline rises to the text's own ink; nothing else moves
    Read the contractFocus:focus-visiblefocus.ringThe shared ring on the link's radius.small box — keyboard only

    There is no disabled state: an anchor cannot be disabled, and a destination that is unavailable is not a link — render it as plain text. Visited is deliberately unstyled; :visited exposes browsing history and browsers restrict what it can paint, so the base leaves it alone and a consumer that genuinely needs it owns that decision.

    In prose

    A link is only ever seen inside running text, so the canvas shows it there rather than standing alone — at the paragraph's own size, weight, and line height, wrapping with the line like any other word.

    Link · In prose

    Components are built from the color roles and the type scale, and re-decide nothing.

    Links inherit the prose's size, weight, and foreground. Nothing separates them from the sentence but the quieter same-hue underline — which is why the rest state keeps it.

    Usage notes

    A link names where it goes and then goes there.

    VerdictRule
    DoUse a link to navigate and a button to act — if the target cannot be opened in a new tab, it is a button.
    DoAlways ship a real href. A span or button styled as a link loses middle-click, copy-link, and keyboard semantics.
    DoKeep the underline. Color alone never marks a link, and in the monochrome default there is no color difference at all.
    DoLet the parent own contrast. Link inherits the surrounding foreground; use --ds-link-color only when an alternate ink has been contrast-gated on that exact surface.
    DoWrite the destination into the label — never “click here”, “read more”, or a bare URL, which are meaningless out of context and to a screen reader listing links.
    DoLet the link inherit the prose's size and weight; a link that needs its own scale is a button or a nav item.
    DoMark links that leave the page or open a new tab in the label or with an adjacent icon, so the jump is not a surprise.
    Don’tNest a link inside a button or a button inside a link — the activation target becomes ambiguous for pointer and keyboard alike.
    Don’tRestyle :visited in the base; it leaks history and browsers restrict it. A consumer that needs it owns the decision.
    Previous · ComponentsInput field Next · ComponentsLoading dots