Zetta v1.6

Components · Text & content

Link

An inline text link in the Primary role — underlined at a 3px offset, inheriting the surrounding type. A standalone variant pairs it with an icon for navigational links that sit on their own. Always underlined, so it never relies on colour alone.

Preview

Build with the skill

No package to install — hand this to your AI to generate or migrate the component in your stack.

Prompt for your AI
Apply the Zetta "Link" component to this project using the zetta-design-md skill.

WHEN TO USE
- Migrating or fixing existing code (the common case): audit the current implementation against the `link` spec (variants: default, standalone, disabled) and CORRECT every deviation — replace off-spec values, don't only add new ones.
- New component: build it to the `link` spec in this project's stack.

AUDIT & FIX (when the component already exists)
Compare it to the skill's spec and fix, don't just append: hardcoded colors/hex, off-scale radius, wrong fonts, dark/navy fills, shadows used in place of borders (or missing borders), brand lime used as a CTA or interaction (must be primary indigo), and any missing or wrong hover / focus / active / disabled / invalid state or missing 2px focus ring. Replace each with the correct Zetta token.

ALWAYS
- Pull the authoritative spec and tokens from the skill — never guess or hardcode values.
- Use this project's own component conventions and framework idioms.
- Honor the Zetta guardrails (brand = identity only, primary = interaction, shadows for overlays) and verify in Light, Dark, and Accessibility.

Anatomy & rules

This is body text with an [inline link] inside it.

[Standalone link →]   ← link-standalone with trailing icon
State Text color Decoration Notes
Default {colors.primary} None
Hover {colors.primary} at 75% opacity Underline
Focus {colors.primary} + 2px solid {colors.border-focus} None Keyboard only
Active {colors.primary-active} Underline Mouse down
Visited {colors.primary} at 75% opacity None Optional — product decision

When to use

  • Navigation to another page, route, or external resource.
  • Inline references within documentation or description text.

When not to use

  • Triggering actions (submit, delete, open modal) — use Button or Link Button.
  • When no href is provided — that is a button, not a link.

Do

  • Use descriptive link text that makes sense out of context: "View project settings", not "Click here".
  • Add rel="noopener noreferrer" for all target="_blank" links.
  • Use standalone variant when the link is not embedded in a paragraph.

Don't

  • Don't use <a> without href — it removes keyboard accessibility.
  • Don't use vague link text like "here", "this", "more", or "read more" without context.
  • Link text should describe the destination or action: "Project settings", "API documentation".
  • For external links, indicate they open in a new tab: "View on GitHub (opens new tab)" or use an external-link icon with aria-label.
  • Max 5–7 words per link label.

Keyboard

Key Behavior
Tab Move focus to the link
Enter Follow the link destination

Accessibility

  • ARIA role: implicit role="link" on <a href>. Never use <button> styled as a link for navigation.
  • New tab: announce to screen readers — add aria-label="[Link text] (opens in new tab)" or include visually hidden text.
  • Visited: link-visited opacity change is a visual-only affordance. Do not rely on it for screen readers.
  • Contrast: {colors.primary} (#5155C6) on white = 6.06:1 (AA). Underline provides additional non-color differentiation.

Spec

Values and token references resolved straight from the Zetta spec.

link
textColor
{colors.primary}
fontFamily
inherit
fontSize
inherit
fontWeight
inherit
textDecoration
underline
textUnderlineOffset
3px
cursor
pointer
link-hover
textColor
{colors.primary}
opacity
0.75
textDecoration
underline
link-focus
outline
2px solid {colors.border-focus}
outlineOffset
2px
borderRadius
2px
link-visited
textColor
{colors.primary}
opacity
0.6
link-disabled
textColor
{colors.disabled-text}
textDecoration
none
cursor
not-allowed
pointerEvents
none
link-standalone
fontFamily
Geist
fontSize
14px
fontWeight
500
display
inline-flex
alignItems
center
gap
{spacing.xs}