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.
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-linkis text-only. Usebutton-link-iconfor 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>withouthref— it removes keyboard accessibility. - Disabled: use
disabledattribute andpointerEvents: 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-linkon dark surface contrast —{colors.primary}(#818cf8 on dark) should be verified.