Zetta v1.6

Components · Data display & feedback

Accordion

Vertically stacked interactive items that expand and collapse to reveal or hide content. New component in v1.4.

Preview

What is Zetta?
A token-first design system delivered as a skill — three themes and ~70 components.
How do I use it?
Install the plugin and let your AI apply the skill in your own stack.
Is there a package?
No — Zetta ships tokens and specs, not a shared component library.

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 "Accordion" 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 `accordion` spec and CORRECT every deviation — replace off-spec values, don't only add new ones.
- New component: build it to the `accordion` 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

┌───────────────────────────────────────┐
│ Accordion Item 1 header        [▼]    │  ← accordion-trigger (closed)
├───────────────────────────────────────┤
│ Accordion Item 2 header        [▲]    │  ← accordion-trigger (open)
│   Content for item 2...               │  ← accordion-content
│   More content here.                  │
├───────────────────────────────────────┤
│ Accordion Item 3 header        [▼]    │  ← accordion-trigger (closed)
└───────────────────────────────────────┘

When to use

  • FAQ sections.
  • Settings panels with grouped options.
  • Navigation sub-menus in sidebar or documentation.
  • Long-form content that benefits from progressive disclosure.

When not to use

  • When all content should be visible — use a plain list.
  • When the user needs to compare content across sections — collapsed content makes comparison harder.
  • When there are fewer than 3 items — just show the content.

Do

  • Keep accordion trigger labels concise — they should tell the user exactly what's inside.
  • Default the most important section to open in forms or settings.
  • Use type="single" for FAQ (only one answer at a time); type="multiple" for settings (user may need multiple sections).

Don't

  • Don't nest accordions more than one level deep.
  • Don't use accordion for primary page navigation.
  • Don't use accordions for content that users need to scan across sections simultaneously.
  • Trigger labels: noun or short question. "Billing", "How do I reset my password?".
  • Keep triggers scannable — users read triggers to decide which to open.
  • Content body: any component is valid inside accordion content.
  • Avoid putting critical information inside a closed accordion — it may be missed.
  • Do not truncate trigger text — wrap instead.

Keyboard

Key Behavior
Tab Move focus to the next accordion trigger
Shift+Tab Move focus to the previous accordion trigger
Enter / Space Toggle the focused item's expanded state
Down Arrow Move focus to the next trigger
Up Arrow Move focus to the previous trigger
Home Move focus to the first trigger
End Move focus to the last trigger

Arrow key navigation between triggers is an enhancement, not a replacement for Tab.

Accessibility

  • Trigger ARIA: role="button", aria-expanded="true/false", aria-controls="panel-id"
  • Panel ARIA: role="region", aria-labelledby="trigger-id", id="panel-id"
  • tabIndex={0} on each trigger so each is independently focusable in natural document order.
  • Contrast: {colors.ink} on transparent ({colors.canvas}) is 18.92:1 (AAA). {colors.primary} on {colors.primary-bg} open state is 5.42:1 (AA).

Spec

Values and token references resolved straight from the Zetta spec.

accordion-root
width
100%
borderRadius
{rounded.base}
overflow
hidden
accordion-item
borderBottom
1px solid {colors.hairline}
accordion-item-last
borderBottom
none
accordion-trigger
display
flex
alignItems
center
justifyContent
space-between
width
100%
paddingX
{spacing.md}
paddingY
{spacing.sm}
backgroundColor
transparent
textColor
{colors.ink}
fontFamily
Geist
fontSize
14px
fontWeight
500
lineHeight
1.5
cursor
pointer
borderRadius
0
transition
background-color {motion.duration-fast} {motion.easing-default}
accordion-trigger-hover
backgroundColor
{colors.surface-muted}
textColor
{colors.ink}
accordion-trigger-focus
outline
2px solid {colors.border-focus}
outlineOffset
-2px
accordion-trigger-open
backgroundColor
{colors.primary-bg}
textColor
{colors.primary}
accordion-trigger-selected
backgroundColor
{colors.primary-bg}
textColor
{colors.primary}
borderLeft
2px solid {colors.primary}
accordion-trigger-disabled
textColor
{colors.disabled-text}
cursor
not-allowed
opacity
0.5
accordion-icon
iconSize
{icons.sizeMap.sm}
textColor
inherit
transition
transform {motion.duration-fast} {motion.easing-default}
accordion-icon-open
transform
rotate(180deg)
accordion-content
paddingX
{spacing.md}
paddingBottom
{spacing.md}
paddingTop
0
textColor
{colors.body}
fontFamily
Geist
fontSize
14px
lineHeight
1.6
overflow
hidden
transition
height {motion.duration-base} {motion.easing-default}