Accordion
import { Accordion } from '@absoluteui/components/accordion';import '@absoluteui/components/accordion/style.css';Using Angular? See Accordion for Angular.
What it does
Section titled “What it does”Vertically stacked headers that each show or hide a section of content, following the WAI-ARIA APG Accordion pattern. Every header is a native heading containing a native <button>, so Tab, Enter, and Space work without scripting tricks. Supports single or multiple expansion, an optional “always one open” mode, and an animated height transition that is removed under reduced motion.
When to use
Section titled “When to use”- Long pages where users need only some sections at a time, such as FAQs or settings groups.
- Progressive disclosure of secondary details in a constrained space.
When not to use
Section titled “When not to use”- Content users must read or compare side by side: show it on the page.
- Switching between peer views of the same content: use Tabs.
- A single show/hide toggle: a native <details> element is enough.
- Navigation menus: use a navigation component.
Examples
Section titled “Examples”FAQ (single mode)
Section titled “FAQ (single mode)”import { Accordion } from '@absoluteui/components/accordion';
const host = document.createElement('div');document.body.append(host);Accordion.create(host, { headingLevel: 2, value: ['shipping'], items: [ { id: 'shipping', title: 'How long does shipping take?', content: 'Orders ship within two business days.' }, { id: 'returns', title: 'Can I return an item?', content: 'Returns are free for 30 days.' }, ],});Several open panels with rich content and change tracking
Section titled “Several open panels with rich content and change tracking”import { Accordion, type AccordionChangeDetail } from '@absoluteui/components/accordion';
const details = document.createElement('p');details.textContent = 'Rich content is passed as a Node.';const host = document.createElement('div');document.body.append(host);const accordion = Accordion.create(host, { multiple: true, items: [ { id: 'profile', title: 'Profile', content: details }, { id: 'billing', title: 'Billing', content: 'Billing settings', disabled: true }, ],});host.addEventListener('aui-change', (event) => { const { value } = (event as CustomEvent<AccordionChangeDetail>).detail; host.dataset.open = value.join(',');});accordion.expand('profile');Default heading level for the application
Section titled “Default heading level for the application”import { configureAbsoluteUI } from '@absoluteui/core';
configureAbsoluteUI({ components: { accordion: { headingLevel: 2 } } });import { Accordion, type AccordionChangeDetail } from '@absoluteui/components/accordion';import '@absoluteui/components/accordion/style.css';
const host = document.querySelector<HTMLElement>('#settings');if (host) { Accordion.create(host, { multiple: true, items: [ { id: 'profile', title: 'Profile', content: 'Name and photo' }, { id: 'privacy', title: 'Privacy', content: 'Who can see your activity' }, ], }); host.addEventListener('aui-change', (event) => { host.dataset.open = (event as CustomEvent<AccordionChangeDetail>).detail.value.join(','); });}More usage
Section titled “More usage”import { Accordion } from '@absoluteui/components/accordion';
const host = document.createElement('div');document.body.append(host);Accordion.create(host, { headingLevel: 2, items: [ { id: 'shipping', title: 'How long does shipping take?', content: 'Orders ship within two business days.' }, { id: 'returns', title: 'Can I return an item?', content: 'Returns are free for 30 days.' }, ],});Anatomy
Section titled “Anatomy”<div class="aui-accordion"> (consumer host) <div class="aui-accordion__item [--expanded] [--disabled]"> <h3 class="aui-accordion__heading"> (headingLevel) <button class="aui-accordion__trigger" aria-expanded aria-controls=panel id=trigger> <span class="aui-accordion__title">Title</span> <svg class="aui-icon aui-accordion__icon" aria-hidden="true"> </button> </h3> <div class="aui-accordion__panel" id=panel role="region" aria-labelledby=trigger hidden> <div class="aui-accordion__clip"> <div class="aui-accordion__content">content</div> </div> </div> </div></div>API reference
Section titled “API reference”Factory
Section titled “Factory”Accordion.create(host: HTMLElement, options: AccordionOptions): AccordionGlobal configuration key: accordion (see Configuration).
Options
Section titled “Options”| Option | Type | Default | Description |
|---|---|---|---|
items |
readonly { id: string; title: string; content: Node | string; disabled?: boolean }[] |
Items with unique ids. Titles and string content render as text. Required. | |
value |
readonly string[] |
"[]" |
Expanded item ids (at most one when multiple is false). |
icons |
Partial<{ expand: IconRef }> |
Icon slot overrides. | |
multiple |
boolean |
false |
Allow several panels open at once; otherwise expanding one collapses the others. Globally configurable. |
collapsible |
boolean |
true |
Single mode: the open panel can be collapsed. When false its header is aria-disabled. Globally configurable. |
headingLevel |
2 | 3 | 4 | 5 | 6 |
3 |
Heading element wrapping each header button. Globally configurable. |
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
host |
HTMLElement |
Consumer host; its children are owned by the component. |
value |
string[] |
Expanded item ids, in item order. |
options |
Readonly<AccordionOptions> |
Current instance options. |
Methods
Section titled “Methods”| Method | Description |
|---|---|
panel(id: string): HTMLDivElement | null |
Content container of an item’s panel. |
expand(id: string): void |
Expand programmatically (no events); collapses others in single mode. |
collapse(id: string): void |
Collapse programmatically (no events), even when not collapsible. |
toggle(id: string): void |
Expand or collapse programmatically (no events). |
update(options: Partial<AccordionOptions>): void |
Merge and apply options. |
destroy(): void |
Remove rendering, listeners, and subscriptions. |
Events
Section titled “Events”| Event | Detail | Bubbles | Cancelable | Description |
|---|---|---|---|---|
aui-change |
{ value: string[]; id: string; expanded: boolean } |
Yes | No | The user expanded or collapsed an item. |
Content areas
Section titled “Content areas”| Area | Description |
|---|---|
panel |
Item content (the content option, or accordion.panel(id)). |
CSS classes
Section titled “CSS classes”All rules live in the aui.components cascade layer, so application styles override them without specificity battles.
| Class | Purpose |
|---|---|
aui-accordion |
Host. |
aui-accordion--animated |
Set after the first toggle; enables the expand transition. |
aui-accordion__item |
Item wrapper. |
aui-accordion__item--expanded | --disabled |
Item state modifiers. |
aui-accordion__heading |
Heading element (h2 to h6). |
aui-accordion__trigger |
Header button. |
aui-accordion__title |
Header text. |
aui-accordion__icon |
Expand indicator (rotates when expanded). |
aui-accordion__panel |
Panel (region when six items or fewer). |
aui-accordion__clip |
Grid row that clips content during the height transition. |
aui-accordion__content |
Content container. |
Icon slots
Section titled “Icon slots”| Slot | Default icon |
|---|---|
expand |
chevron-down |
Design tokens
Section titled “Design tokens”Tokens this stylesheet reads (verified in CI). Override them in a theme or with the Theme Designer.
--aui-border-width | --aui-color-border | --aui-color-focus-ring | --aui-color-hover | --aui-color-text | --aui-color-text-disabled | --aui-color-text-muted | --aui-control-height-lg | --aui-duration-fast | --aui-duration-normal | --aui-easing-standard | --aui-focus-ring-offset | --aui-focus-ring-width | --aui-font-family-sans | --aui-font-size-md | --aui-font-size-sm | --aui-font-weight-medium | --aui-icon-size-sm | --aui-line-height-normal | --aui-line-height-tight | --aui-space-3 | --aui-space-4
TypeScript definitions
Section titled “TypeScript definitions”type AccordionHeadingLevel = 2 | 3 | 4 | 5 | 6;interface AccordionItem { id: string; title: string; content: Node | string; disabled?: boolean }interface AccordionOptions { items: readonly AccordionItem[]; value?: readonly string[]; multiple?: boolean; collapsible?: boolean; headingLevel?: AccordionHeadingLevel; icons?: Partial<{ expand: IconRef }> }interface AccordionChangeDetail { value: string[]; id: string; expanded: boolean }Accessibility
Section titled “Accessibility”Pattern: WAI-ARIA APG Accordion pattern: native heading elements containing native buttons that control panels.
Keyboard
Section titled “Keyboard”| Key | Context | Action |
|---|---|---|
| Tab / Shift+Tab | Any | Moves through header buttons and focusable panel content in document order. |
| Enter / Space | Header button focused | Expands or collapses the panel (native button activation). |
| ArrowDown / ArrowUp | Header button focused | Moves focus to the next or previous header, wrapping (APG optional). |
| Home / End | Header button focused | Moves focus to the first or last header (APG optional). |
| Element | Role |
|---|---|
| heading | heading (native h2 to h6, headingLevel) |
| header button | button (native) |
| panel | region when there are six items or fewer; otherwise none |
| indicator icon | none (aria-hidden=true) |
ARIA attributes
Section titled “ARIA attributes”| Attribute | Element | Value |
|---|---|---|
aria-expanded |
header button | “true” when the panel is shown, otherwise “false” |
aria-controls |
header button | Panel id |
aria-disabled |
header button | “true” for disabled items, and for the open item in single non-collapsible mode |
aria-labelledby |
panel | Header button id |
hidden |
panel | Present while collapsed |
Header buttons show a :focus-visible inset outline. Disabled and locked headers stay focusable so their state is discoverable. Re-rendering keeps focus on the same header.
WCAG 2.2 success criteria addressed
Section titled “WCAG 2.2 success criteria addressed”| Criterion | Level | Note |
|---|---|---|
| 1.3.1 Info and Relationships | A | |
| 1.4.11 Non-text Contrast | AA | |
| 2.1.1 Keyboard | A | |
| 2.4.3 Focus Order | A | |
| 2.4.6 Headings and Labels | AA | |
| 2.4.7 Focus Visible | AA | |
| 2.3.3 Animation from Interactions | AAA | |
| 4.1.2 Name, Role, Value | A |
Automated test results: Accessibility and compliance.
Notes and known caveats
Section titled “Notes and known caveats”- Panels use role=region only for six items or fewer, following APG guidance against landmark proliferation.
- Arrow keys are handled only on header buttons, never inside panel content.
- The height transition and icon rotation animation are removed under prefers-reduced-motion and animation ‘none’.
- Manual screen-reader verification (NVDA, JAWS, VoiceOver) is pending.
Behavior
Section titled “Behavior”States
Section titled “States”collapsed, expanded, expanded and locked (single, non-collapsible), disabled item, hover, focus-visible.
State transitions
Section titled “State transitions”| From | Trigger | To |
|---|---|---|
| collapsed | user activates header | expanded; in single mode the open item collapses; aui-change |
| expanded | user activates header (collapsible or multiple) | collapsed; aui-change |
| expanded (single, non-collapsible) | user activates header | no change (header is aria-disabled) |
| any | expand / collapse / toggle / update({ value }) |
new state; no events |
| multiple, several open | global config switches to single | only the first open item stays expanded |
Accessibility notes
Section titled “Accessibility notes”- Headers are real headings; set
headingLevelto fit the page outline. - Disabled and locked headers stay focusable (
aria-disabled, notdisabled) so their state is discoverable. - Re-rendering (for example a new
headingLevel) keeps focus on the same header. - The height transition and the icon rotation animation are removed under
prefers-reduced-motionandanimation: 'none'; the rotated icon remains as a static indicator. - Manual screen-reader verification is pending (see Known limitations).
Responsive behavior
Section titled “Responsive behavior”Full width of its container. Long titles wrap; the indicator stays at the inline end.
Right-to-left
Section titled “Right-to-left”Logical properties throughout. The title is at the inline start and the indicator at the inline end.
Theming
Section titled “Theming”Colors come from role tokens only. In forced-colors mode borders use CanvasText, focus uses a Highlight outline, and disabled headers use GrayText.
Global configuration
Section titled “Global configuration”configureAbsoluteUI({ components: { accordion: { multiple: true, headingLevel: 2 } } });Changes apply to existing instances immediately.
Component configuration
Section titled “Component configuration”Instance options override global and theme defaults. All options are dynamic.
icons.expand (default chevron-down); rotated 180 deg while expanded.
Security
Section titled “Security”Titles and string content use textContent and are never parsed as HTML. Node content is inserted as-is; sanitizing it is the consumer’s responsibility. CSP-safe: no inline styles or handlers.
Data handling
Section titled “Data handling”No persistence, network access, or telemetry.
Performance
Section titled “Performance”Two delegated listeners on the host (click, keydown) and one configuration subscription, regardless of item count. State changes update attributes in place; only items, headingLevel, or icons changes re-create the item DOM. Budget: under 5 ms for 50 items (not yet covered by the performance test).
Supported data scale
Section titled “Supported data scale”Designed for tens of items. Unit-tested with up to seven items.
Edge cases
Section titled “Edge cases”valuewith more than one id in single mode throwsACCORDION_OPTIONS.- An empty
itemsarray renders an empty host. - Programmatic
collapseis allowed in non-collapsible mode; only user interaction is locked. - A disabled item can still be expanded programmatically.
- Node content is moved into the panel, not cloned; passing the same Node to two items keeps it in the last one.
Errors
Section titled “Errors”| Code | Category | Cause |
|---|---|---|
ACCORDION_OPTIONS |
configuration | Missing or duplicate ids, empty title, unknown ids in value, or several ids in single mode. |
ACCORDION_ITEM |
configuration | expand, collapse, or toggle with an unknown id. |
CFG_INVALID_VALUE |
configuration | Invalid multiple, collapsible, or headingLevel value. |
A failed construction leaves no rendering, listeners, or subscriptions behind.
Known limitations
Section titled “Known limitations”- Collapsed content is not found by find-in-page (
hidden, nothidden="until-found"). - Changing
itemsre-creates the item DOM. - Screen-reader behavior has not yet been manually verified with NVDA, JAWS, and VoiceOver.
Unsupported scenarios
Section titled “Unsupported scenarios”- HTML strings as titles or content (pass a Node).
- Interactive content inside headers.