Zetta v1.6

Components · Actions

Toggle

A button with an on/off state, driven by aria-pressed — for formatting controls and view switches. It reads as a ghost button when off and holds a muted fill when on. Group several into a toolbar segment for mutually-related options.

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

┌────────────┐
│    [icon]  │  ← 32px height, transparent at rest
└────────────┘
  Fill 0 (outlined) at rest
  Fill 1 (filled) when pressed
State Background Text Notes
Default (unpressed) transparent {colors.muted} Outlined icon
Hover {colors.primary-bg} {colors.primary}
Focus transparent + 2px solid {colors.border-focus} {colors.muted} Keyboard only
Active (click down) {colors.surface-pressed} {colors.ink} Momentary press
Pressed (sustained) {colors.surface-muted} {colors.ink} Filled icon (Fill 1)
Pressed hover {colors.primary-bg} {colors.primary} Hovered while pressed
Disabled {colors.disabled-bg} {colors.disabled-text} not-allowed

Note: toggle-active (momentary click) and toggle-pressed (sustained on) are intentionally different. Do not normalize them.

When to use

  • Toolbar actions that persist state visually: bold, italic, filter on/off, view mode switch.
  • Icon-only buttons where the pressed state is meaningful and must be communicated.

When not to use

  • For boolean form fields that submit a value — use Toggle Switch.
  • For navigation — use sidebar or tab nav.
  • For actions without a persistent pressed state — use Icon Button.

Do

  • Always pair with a tooltip showing the action name.
  • Use icons that have both outlined and filled variants in Material Symbols.
  • Reflect the pressed state from application state — do not manage internally.

Don't

  • Don't use Toggle for actions that require confirmation.
  • Don't use Toggle for navigation or page transitions.
  • aria-label: action verb — "Bold", "Toggle filter", "Italic".
  • Tooltip: must match aria-label exactly.
  • aria-pressed value changes: announce via aria-live if the change is not visually obvious.

Keyboard

Key Behavior
Tab Move focus to toggle
Space Toggle pressed state
Enter Toggle pressed state

Accessibility

  • ARIA role: role="button" with aria-pressed="true" or aria-pressed="false".
  • aria-label required — the icon alone is not accessible.
  • aria-disabled="true" on disabled toggles.
  • Focus ring: 2px solid {colors.border-focus} at 2px offset.

Spec

Values and token references resolved straight from the Zetta spec.

toggle
backgroundColor
transparent
textColor
{colors.muted}
borderColor
transparent
borderWidth
1px
borderRadius
{rounded.base}
fontFamily
Geist
fontSize
14px
fontWeight
500
height
32px
minWidth
32px
iconSize
16px
cursor
pointer
toggle-hover
backgroundColor
{colors.primary-bg}
textColor
{colors.primary}
toggle-active
backgroundColor
{colors.surface-pressed}
toggle-pressed
backgroundColor
{colors.surface-muted}
textColor
{colors.ink}
toggle-pressed-hover
backgroundColor
{colors.primary-bg}
textColor
{colors.primary}
toggle-focus
outline
2px solid {colors.border-focus}
outlineOffset
2px
toggle-disabled
textColor
{colors.disabled-text}
cursor
not-allowed