EDS 0.x
Components

Accordion

Examples

Contained (default)

Card chrome with border, radius, and shadow. Items are spaced with an 8px gap.

Download invoices from the billing console. Seats renew on your contract anniversary.

Lined

Hairline dividers without card chrome — useful under a section heading (FAQ).

Frequently asked questions

Stacked

Joined group with shared borders. First/last corners are handled automatically — no position prop.

Public IPs, VLANs, and interconnects assigned to this metro.

Icon & badge

Optional leading icon and trailing badge before the chevron. Until EDS ships icons, demos use Quix.

Controlled

Drive open items with value / onValueChange. Values are string arrays.

Open: one

Panel one

Disabled

Disable the whole accordion or a single item.

RTL

The trigger is a horizontal flip of LTR: leading icon + title + badge on the inline-start edge, chevron on the inline-end (visually left in RTL).

محتوای پنل اول برای نمایش جهت خواندن راست‌به‌چپ.

API Reference

Built on Base UI Accordion.

Accordion

PropTypeDefaultDescription
variant"contained" | "lined" | "stacked""contained"Visual treatment from Figma
multiplebooleanfalseAllow more than one item open
valuestring[]Controlled open item values
defaultValuestring[]Uncontrolled initial open values
onValueChange(value: string[], eventDetails) => voidFires when open set changes
disabledbooleanfalseDisables every item
keepMountedbooleanfalseKeep closed panels in the DOM
hiddenUntilFoundbooleanfalseExpose closed panels to find-in-page
classNamestringExtra classes on the root
idstringRoot id
aria-labelstringAccessible name for the group
aria-labelledbystringId of a visible label / heading

Accordion.Item

PropTypeDefaultDescription
valuestringautoUnique value for open state
disabledbooleanfalseDisables this item only
onOpenChange(open: boolean, eventDetails) => voidPer-item open callback
classNamestringExtra classes on the item

Accordion.Trigger

Renders an <h3> header wrapping the expand/collapse <button>. Chevron chrome is built in.

PropTypeDefaultDescription
childrenReactNodeTitle content
iconReactNodeLeading decorative icon (aria-hidden wrapper)
badgeReactNodeTrailing badge before the chevron
classNamestringExtra classes on the button
idstringTrigger id

Accordion.Panel

PropTypeDefaultDescription
childrenReactNodePanel body (content slot)
classNamestringExtra classes on the panel
keepMountedbooleaninheritsOverride root keepMounted
hiddenUntilFoundbooleaninheritsOverride root hiddenUntilFound

Accessibility

WCAG success criteria

CriterionLevelHow EDS helps
2.1.1 KeyboardATriggers are native buttons; Space/Enter toggles
2.4.7 Focus VisibleAAItem-level focus ring via :focus-visible
4.1.2 Name, Role, ValueAaria-expanded, header/button pairing, panel association from Base UI
1.3.1 Info and RelationshipsAHeading (h3) wraps each trigger; panels are labeled regions
1.4.3 Contrast (Minimum)AATitle/body use semantic text tokens
1.4.11 Non-text ContrastAABorders, chevron, and focus outline use outline/border tokens
2.4.3 Focus OrderADOM order matches visual order; respects dir
2.2.2 Pause, Stop, HideAHeight animation respects prefers-reduced-motion

Why it matters

Accordions hide content by default. Without a real button, aria-expanded, and a heading structure, keyboard and screen-reader users cannot predict what will open, whether content is already visible, or how sections relate. Clear triggers and panels keep long FAQs and settings groups scannable without trapping focus or dumping every panel into the tab order at once.

Keyboard

KeyBehavior
⇥ Tab / + ⇥ TabMoves focus between triggers (and into focusable content inside an open panel)
Space / ↵ EnterExpands or collapses the focused item
⎋ EscapeDoes not auto-close (APG pattern for disclosure-style accordion)

Arrow-key roving focus is not used (aligned with current APG guidance and Base UI).

Screen readers & semantics

Built on Base UI Accordion:

SurfaceImplementation
TriggerNative <button> with aria-expanded and aria-controls
Header<h3> via Accordion.Trigger (adjust page heading levels so this nests correctly)
PanelRegion associated with its trigger; unmounted when closed unless keepMounted / hiddenUntilFound
Icon / chevronDecorative wrappers use aria-hidden="true"
BadgeAnnounced as part of the button name when it is text

Prefer a page heading + aria-labelledby on the root when a visible “FAQ” title already exists. Use hiddenUntilFound if closed answers must appear in browser find-in-page.

Focus & visuals

ConcernEDS behavior
Focus ring2px outline-primary on the item when the trigger is :focus-visible
ExpandedChevron rotates 180°; Contained/Stacked show a header/content separator
Hoveradaptive-8 wash on the trigger
Disabledtext-disabled; trigger is not activatable
RTLInherits ancestor dir via Base UI DirectionProvider — full horizontal flip of the trigger
MotionPanel height animates; disabled under prefers-reduced-motion

Build with it

DoDon’t
Put meaningful titles in Accordion.TriggerUse vague labels like “Click here” or duplicate titles
Keep panel content short and scannableBury entire multi-step forms in a single panel
Use variant="lined" under a section heading for FAQsNest accordions inside accordion panels without strong need
Mark decorative icons aria-hidden (EDS wraps icon)Put interactive controls inside the trigger
Choose multiple intentionally for the taskForce exclusive mode when users need to compare open sections

Quick test

  1. Keyboard — Tab through triggers, toggle with Space/Enter, confirm focus can enter open panel content.
  2. Screen reader — Verify expanded/collapsed state and that panel content is announced when opened.
  3. Find-in-page — With hiddenUntilFound, search for text in a closed panel and confirm it expands.
  4. RTL — Open the RTL example; confirm the row is mirrored (chevron on the left, title/icon on the right).
  5. Motion — Enable reduced motion and confirm panels open without height animation.

On this page