Skip to main content

Design system components

ExpandableSection

Collapsible content region with a trigger header. Lighter than Accordion (which manages a group of expandables); used standalone for a single 'show more' or detail-disclosure section.

Status: stable. Group: structure. Markdown version: /design-system/components/expandable-section.md

When to use

ExpandableSection is a single, independent disclosure: one trigger whose label can swap between states (collapsedLabel/expandedLabel), revealing its children with a height and fade transition while the content slides up slightly. Use it for "show more" tails: extended bios, optional details, long changelogs. It has no group behavior: several ExpandableSections don't know about each other. When sections should be exclusive (open one, close the other), that is Accordion.

When not to use

  • Do not use a sequence of ExpandableSections instead of Accordion; accordion owns the focus management and single-open behaviour.
  • Do not hide critical content (errors, primary CTA) behind a disclosure.

Look-alikes

  • Accordion: Do not build exclusive groups from several ExpandableSections; that is Accordion's contract.

Props

ExpandableSection props
PropTypeDefaultDescriptionRequired
collapsedLabelstringnoneTrigger label when collapsed.Yes
expandedLabelstringnoneTrigger label when expanded (optional, defaults to collapsedLabel)No
defaultExpandedbooleanfalseWhether the section is initially expanded.No
expandedbooleannoneControlled expanded state.No
onExpandedChange(expanded: boolean) => voidnoneCallback when expansion state changes.No
childrenReactNodenoneContent to reveal.Yes
classNamestringnoneAdditional className for the container.No

Variants

No variant dimensions and no props with a fixed set of values.

Invalid combinations

  • MUST NOT: expanded and defaultExpanded set together. expanded makes the component controlled and defaultExpanded uncontrolled; pass one, not both.

Keyboard

ExpandableSection keyboard behaviour
KeyBehaviour
TabFocuses the trigger header.
Enter / SpaceToggles the section.

Rules

Every item under When not to use is a MUST NOT. MUST and SHOULD follow RFC 2119.

ExpandableSection rules
LevelRuleHow it is checked
MUST NOTexpanded and defaultExpanded set together. expanded makes the component controlled and defaultExpanded uncontrolled; pass one, not both.Checked by the MCP tool validate_component_usage.
MUSTARIA: Trigger is a <button> with aria-expanded reflecting the open state.Not yet verified: no evidence record. WCAG 4.1.2.
MUSTARIA: The panel is added/removed on toggle (no dangling aria-controls); the trigger's text label is its accessible name.Not yet verified: no evidence record. WCAG 4.1.2.
MUSTRequired stories produce no axe violations at the configured severity.Automated by npm run test:stories:matrix:ci. WCAG 2.5.8.
MUSTThe accessibility tree (role, name, state) matches the committed snapshot for every required story.Automated by npm run test:stories:matrix:ci. WCAG 1.3.1, 4.1.2.
MUSTThe component remains legible and operable under a real browser forced-colors: active pass.Automated by npm run test:stories:hc.
MUSTPositional, scale, and opacity motion is suppressed under prefers-reduced-motion.Manual review, last on 2026-11-04. WCAG 2.2.2, 2.3.3.
MUSTEvery documented keyboard interaction works as specified.Not yet verified: no evidence record. WCAG 2.1.1, 2.1.2.
MUSTA human completed an end-to-end accessibility review of this component.Manual review, last on 2026-11-04.
SHOULDGive expandedLabel the inverse verb ("Show less") so the trigger always states what it will do.Not stated in the contract.
SHOULDUse it for optional tails of content, not for the content's opening.Not stated in the contract.
SHOULDUse controlled mode (expanded + onExpandedChange) when analytics or URL state care about the disclosure.Not stated in the contract.
SHOULDKeep the reveal short; dozens of children behind one disclosure read as lag; split long lists instead.Not stated in the contract.
SHOULD NOTDo not build exclusive groups from several ExpandableSections; that is Accordion's contract.Not stated in the contract.
SHOULD NOTDo not hide required form fields inside; validation errors in collapsed content are invisible.Not stated in the contract.

Install and import

  • Install: npm install @digitaltableteur/react (version 0.9.1, restricted access on npm).
  • Import: import { ExpandableSection } from "@digitaltableteur/react";
  • Entry point: @digitaltableteur/react/content exports it too.
  • Styles: import @digitaltableteur/react/style.css once at the app boundary.
  • Also available as the custom element <dt-expandable-section>; see the custom elements manifest.