Designer view

Accordion

A vertically-stacked set of disclosure controls, each pairing a header button with a panel of content that expands or collapses. Distinct from Tabs (always shows one panel, replaces on selection) by allowing zero, one, or multiple panels open at once and by preserving all panel labels on screen. Used for FAQs, settings groupings, progressive disclosure of dense reference content, and any list of named regions where content is browsable but not all needed simultaneously.

When to use

Use

For a list of named regions where content is browsable but not all needed simultaneously — FAQs, settings groupings, progressive disclosure of dense reference content. The user can scan all headers, expand the items they need, and collapse the ones they don't. Accordion preserves all panel labels on screen.

Avoid

For mutually-exclusive parallel views of the same subject (settings tabs, alternative presentations of the same data) — that is `Tabs`. For a single collapsible region not part of a list — that is `Disclosure`. For navigation between independent pages — that is `SidebarNav`. For sequential flows that must complete in order — that is `Stepper`.

Versus related

  • tabs

    `Tabs` always shows one panel and replaces it on selection; `Accordion` allows zero, one, or multiple panels open at once. Tabs are lateral (peer content chunks at the same level); Accordion is hierarchical (each header is a heading in the document outline). Vertical Tabs and single-mode Accordion can look similar — the distinguisher is whether all labels stay visible (Accordion) or only the selected label is emphasised (Tabs).

  • disclosure

    `Disclosure` is a single collapsible region with one toggle; `Accordion` is a list of disclosures grouped as a unit with shared keyboard navigation (ArrowDown / Up between items). A standalone collapsible region is Disclosure, not Accordion-of-one-item.

  • sidebar-nav

    `SidebarNav` navigates between independent pages with their own URLs; `Accordion` discloses inline content within a single page. A nav-style accordion (clicking an item navigates) is a SidebarNav with collapsible sections, not an Accordion.

Highlight
Fig 1.1 · Accordion · Designer view
Designer

Figma anatomy

Slot Figma type Hint
root frame Auto-layout vertical frame; gap and border treatment from variant
item instance Accordion item component instance; expanded state via component property
header text Heading text style; same level for every item in the accordion
trigger instance Button component instance filling the header; bound to expanded state
icon instance Icon component instance; rotation or swap bound to expanded state
panel frame Auto-layout vertical frame; visibility bound to expanded state of the parent item
Designer

Token usage per slot

root
spacing
  • gapspacing.tight
color
  • bordercolor.border.subtle
item
radius
  • cornerradius.md
color
  • backgroundcolor.surface.bg
header
color
  • foregroundcolor.text.primary
typography
  • sizetext.md
  • weightweight.semibold
trigger
spacing
  • paddingspacing.compact
  • gapspacing.compact
color
  • ringcolor.border.focus
icon
color
  • foregroundcolor.text.muted
panel
spacing
  • paddingspacing.compact
color
  • foregroundcolor.text.primary
typography
  • sizetext.md
  • lineHeightleading.normal
Both

Figma ↔ Code property map

FigmaTypeCodeNotes
VariantVariantvariantMaps bordered / contained / flush.
MultiBooleanmultiToggles single-vs-multi-open behaviour. Default false (single-open) for FAQ patterns; true for settings groups.
CollapsibleBooleancollapsibleIn single-open mode, allows the currently-open item to collapse (state with no items expanded). Multi-mode always allows collapse; this property is only meaningful for single-mode.
DensityVariantdensitycomfortable / compact. At and below `breakpoint.sm` density compact is the canonical default.
Item CountVariantitems.lengthFigma exposes 2/3/4/5/6+ item counts as a Variant for preview-time layout review. Code accepts an array of item definitions.
Has IconBooleanhasIconToggles the trigger-icon (chevron / plus-minus) visibility per item.
Default Open ItemsVariantdefaultOpenFigma exposes "first item open", "all items open", "no items open" as Variant for preview; in code it's a configuration prop (single-string id for single-mode, array of ids for multi-mode).
Designer

Motion

TransitionDuration token
expandmotion.duration.base
collapsemotion.duration.base
chevronRotatemotion.duration.fast
Easing
motion.easing.standard
Reduced motion
Instant (jump cut)
Designer

Responsive behaviour

BreakpointChange
breakpoint.smAt and below, density compact becomes the canonical default — narrow viewports cannot accommodate comfortable density without crowding. Trigger padding reduces; panel padding stays consistent. Variant `flush` (no borders, no item gap) is preferred to preserve vertical space.
breakpoint.mdAbove this width, density and variant render as authored. Items render at their authored gap and border treatment.
Both

Internationalisation

RTL · mirroring

Vertical orientation is direction-neutral (top-to-bottom stacking unchanged). Trigger inline-content (heading-text · chevron) reverses logical order — the chevron moves from inline-end (visual right in LTR) to inline-end (visual left in RTL) via logical positioning. ArrowDown / ArrowUp keyboard navigation is unchanged. Chevron rotation is direction-neutral (down/up arrows are symmetric); plus-minus glyph is also direction-neutral.

Text expansion

Trigger heading text wraps to additional lines under heavy expansion (DE / RU / FI). Panel content follows its own text-flow. Density compact risks crowding long-text headings; density comfortable is the safer default in long-text locales. Multi-line trigger headings continue to behave correctly with the chevron icon — the chevron aligns with the first line of the heading by canonical convention.

Both

Variants, properties, states

Variants

Structurally different versions of the component.

borderedcontainedflush

Properties

The same component, parameterised.

PropertyType
multiboolean
collapsibleboolean
densitycomfortable | compact

States

Browser/user-driven (interactive) vs. app-driven (data).

KindStates
interactive
hoverfocus-visibleactivedisabled
data
closedexpandingexpandedcollapsing
Both

State transitions

FromToTrigger
closedexpandingUser activates the trigger (Enter / Space / click) on a closed item. `aria-expanded` flips to true; the panel begins its enter animation.
expandingexpandedThe expand animation completes (or, under prefers-reduced-motion reduce, immediately). The panel is fully visible and reachable by keyboard via Tab.
expandedcollapsingUser activates the trigger on an expanded item (when `collapsible: true` for single-open variant, or always for multi-open variant); or another item is activated in single-open non-collapsible mode and this item collapses to make way.
collapsingclosedThe collapse animation completes (or immediately under reduced motion). The panel is removed from the accessibility tree and from the keyboard tab order via the `hidden` attribute or `display: none`.
Both

Figma↔Code mismatches

  1. 01
    Figma

    Accordion item header drawn as plain text with a chevron icon

    Code

    A real `<button>` inside a `<h2>`/`<h3>`/`<h4>` element with `aria-expanded`

    Consequence

    Designers may treat the header as a styled label with a chevron affordance. Implementations following the Figma file ship a `<div>` with click handler — the click works for mouse users but the entire keyboard, SR, and APG contract is broken (no focus, no Enter/Space activation, no announced state, no heading semantics).

    Correct

    Document the canonical structure as heading-wraps-button. The Figma component must encode "header is heading; trigger is button" — even if the visual treatment puts no button-styling on the trigger, the underlying element is a real `<button>` inside a real heading.

  2. 02
    Figma

    Single-open and multi-open drawn as the same component

    Code

    A `multi` boolean property toggling whether multiple panels can be open simultaneously

    Consequence

    Designers do not differentiate the two modes in the design file; developers ship one or the other depending on what the Figma mock implies. The mode is canonical-meaningful — single-open accordions imply mutually-exclusive disclosure (FAQ patterns); multi-open imply independent collapsible regions (settings groups). Mixing them confuses users.

    Correct

    Treat `multi` as a first-class property on the canonical reference. Designers and developers both consult the canon to confirm which mode they're using; the Figma component carries `multi` as a Boolean property.

  3. 03
    Figma

    Animated chevron rotation drawn but no panel-height transition

    Code

    Both the chevron rotation AND the panel height-transition animate together

    Consequence

    Designers animate the chevron in mocks but the panel appears instantly (Figma cannot easily mock smooth height-transitions). Developers shipping faithful-to-mock get jumpy panel transitions; SR users get no announcement while the visible content shifts.

    Correct

    Document both animations as canonical: chevron rotation + panel height-transition share the same duration token (per ADR-007 motion). Implementations using `[hidden]` toggle without animation are valid for `prefers-reduced-motion: reduce`.

  4. 04
    Figma

    Each item header drawn at a different heading level for "visual variety"

    Code

    All item headers at the same heading level (consistent with document outline)

    Consequence

    Designers may use h2 for important items, h3 for secondary, h4 for tertiary in the same accordion to create visual hierarchy. Implementations following the design break SR heading navigation (the user expects a flat list of siblings; gets a hierarchy). Heading levels in an accordion communicate document structure, not item importance.

    Correct

    All accordion item headers MUST be the same heading level. Choose the level relative to the document outline (h2 if the accordion is a top-level region; h3 if nested under a top-level h2). Communicate item importance through content order, not heading hierarchy.

Designer

Common mistakes

#accordion-no-heading-wrap

Trigger button not wrapped in a heading element

Problem

The trigger is a `<button>` directly inside a `<div>` or a list item, not wrapped in a heading. SR users navigating by heading skip the accordion entirely; the structure lacks the canonical APG semantics.

Fix

Wrap each trigger in a heading element (`<h2>`, `<h3>`, `<h4>`) of consistent level across all items. The heading is what SR users use to navigate to and within the accordion; the button inside the heading is what carries the toggle behaviour.

#accordion-no-aria-expanded

Trigger missing `aria-expanded` toggle

Problem

The button has no `aria-expanded` attribute. Visually the panel reveals; SR users hear "button" with no state cue, and the icon alone is not discoverable to non-sighted users.

Fix

`aria-expanded="true"` on the button when the panel is open, `false` when closed. Always pair with `aria-controls` referencing the panel's id. Style the icon from `[aria-expanded="true"]` rather than introducing a parallel `data-expanded` attribute.

#accordion-icon-only-state-cue

Expansion state communicated only by chevron rotation

Problem

The chevron rotates on expand, but `aria-expanded` is missing or stuck at one value. Sighted users see the state; SR users do not. The icon is decorative; without `aria-expanded` it carries the entire state-meaning load.

Fix

`aria-expanded` is the source of truth for expansion state; the icon visualises it. The icon is `aria-hidden="true"`; the announced state comes from `aria-expanded`. Style icon rotation from `[aria-expanded="true"]`.

#accordion-multi-vs-single-confusion

Single-open mode silently switches to multi when user expects mutual exclusion

Problem

The accordion's `multi` mode is set by config but not communicated to users. Users expanding one item expect the previously-open item to collapse (single-open assumption); it does not, and the layout grows unexpectedly.

Fix

Choose `multi` mode based on content: single-open for mutually-exclusive content (FAQ patterns), multi-open for independent regions (settings groups). The mode should be visually obvious — single-open's collapse-others behaviour gives a recognisable "only one open" feeling. Avoid switching modes mid-flow; the choice is canonical per use case.

Accessibility hints
Slot Accessibility hint
root The root has no required ARIA role. APG explicitly forbids `role="region"` on the root because the regions live on the panels inside (each panel is its own region). Adding a wrapping role creates redundant landmark navigation.
item Item is a structural grouping; no ARIA role. The header and panel inside carry the canonical APG semantics (heading + button + region).
header Header is a heading element — `<h2>` to `<h4>` depending on document outline. The button inside is what carries `aria-expanded`; the heading itself does not. Using non-heading wrappers (a `<div>` with `role="heading"`) breaks APG conformance.
trigger Real `<button>` — never a `<div>` with click handler. Carries `aria-expanded` reflecting state, `aria-controls` referencing the panel id, and the accessible name from the header text. Disabled headers use `aria-disabled` to stay focusable; sequential focus skips disabled items only via roving tabindex (rare in accordion canon).
icon Decorative — `aria-hidden="true"`. Expansion state is communicated through `aria-expanded` on the trigger and through the panel's visible height; the icon is visual reinforcement only. Icon-only state cues without `aria-expanded` violate APG.
panel Apply `role="region"` with `aria-labelledby` referencing the trigger's id. The panel is hidden via the `hidden` attribute or `display: none` when collapsed (not just zero-height) so SR users do not encounter ghost content. For `motion: collapse` animations, swap `hidden` for a `aria-hidden="true"` plus `pointer-events: none` while the height transition runs, then apply `hidden` at the end.