Zetta v1.6

Components · Actions

Button link

A text-only action styled as an inline link — Primary-coloured, underlined with a 4px offset, no fill or border. Use it for low-emphasis or navigational actions that sit inside running text or beside a primary button.

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 "Button 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 `button-link` spec (variants: default, hover, disabled) and CORRECT every deviation — replace off-spec values, don't only add new ones.
- New component: build it to the `button-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

Click here to [save changes]
                ↑
         button-link (underlined)

Parts:

  • Label — 14px / 500 Geist, {colors.primary}, underlined at rest
  • Focus ring — 2px {colors.border-focus} outline at 2px offset
State Text color Decoration Notes
Default {colors.primary} None
Hover {colors.primary} at 75% opacity Underline
Focus {colors.primary} + 2px solid {colors.border-focus} outline None Keyboard only
Active {colors.primary-active} Underline Mouse down
Visited {colors.primary} at 75% opacity None Optional — product decision
Disabled {colors.disabled-text} None aria-disabled="true"

When to use

  • Inline actions embedded in a sentence or paragraph.
  • Secondary or tertiary actions where a full button would feel too heavy.

When not to use

  • For navigation between pages — use a <a> link element.
  • As a primary action — use button-primary.
  • When the action is destructive — use button-danger.

Do

  • Use action verbs: "Save", "Undo", "View details".
  • Keep labels short — 1–3 words.

Don't

  • Don't add an icon — button-link is text-only. Use button-link-icon for icon+text inline links.
  • Don't use for navigation — it triggers an action, not a route change.
  • Verb or short verb phrase: "Save draft", "Remove filter", "Undo".
  • Sentence case. No trailing punctuation.
  • Do not use generic labels like "Click here" or "Learn more" without context.

Keyboard

Key Behavior
Tab Move focus to the link
Enter Follow the link destination
Space Activate the button

Accessibility

  • ARIA role: implicit role="button" on <button>. Do not use <a> without href — it removes keyboard accessibility.
  • Disabled: use disabled attribute and pointerEvents: none. Do not rely on opacity alone.
  • Contrast: {colors.primary} (#5155C6) on white = 6.06:1 — meets AA for body text.

Spec

Values and token references resolved straight from the Zetta spec.

button-link
backgroundColor
transparent
textColor
{colors.primary}
borderColor
transparent
fontFamily
Geist
fontSize
14px
fontWeight
500
lineHeight
1.4
height
32px
paddingX
0
gap
{spacing.sm}
iconSize
{icons.sizeMap.md}
textDecoration
underline
textUnderlineOffset
4px
cursor
pointer
button-link-hover
opacity
0.75
textDecoration
none
button-link-focus
outline
2px solid {colors.border-focus}
outlineOffset
2px
button-link-disabled
textColor
{colors.disabled-text}
opacity
0.5
textDecoration
none
cursor
not-allowed
pointerEvents
none

Known gaps

  • Visited state — not yet specified.
  • button-link on dark surface contrast — {colors.primary} (#818cf8 on dark) should be verified.