Skip to content

Anatomy ​

Each Disclosure owns one trigger and one panel. A DisclosureGroup is optional and coordinates only the constraints between independently mounted disclosures.

Structure ​

DisclosureGroup (optional)             data-component="DisclosureGroup"
└─ Disclosure (× n)                    data-component="Disclosure"
   ├─ heading                          h2–h6 appropriate to the page outline
   │  └─ trigger                       button[data-ref="trigger"]
   └─ panel                            [data-ref="panel"]

Parts ​

PartSelectorRequiredRole
Groupdata-component="DisclosureGroup"NoCoordinates multiple/collapsible constraints for its closest registered disclosure children.
Disclosuredata-component="Disclosure"YesOwns state, accessibility attributes, focus handling, and local transitions.
HeadingNative heading elementRequired for an accordion patternGives each disclosure trigger an appropriate place in the document outline.
Triggerbutton[data-ref="trigger"]YesToggles the panel and exposes aria-expanded and aria-controls.
Panel[data-ref="panel"]YesContains the disclosed content and is labelled by the trigger.

Use a native <button type="button">; Disclosure warns when the trigger ref is not an HTMLButtonElement. For an accordion, wrap each button in a native heading whose level fits the page hierarchy. The JavaScript component does not create or validate that heading. The Twig template defaults to <h3> and lets you choose heading_tag.

The panel does not receive a region role automatically. Add role="region" only when the extra landmark helps users; avoid creating a large number of unnecessary regions.

IDs and ARIA ​

Authored trigger and panel IDs are preserved. If either ID is missing, Disclosure generates it from the component instance ID, then always sets the trigger's aria-controls to the panel ID and the panel's aria-labelledby to the trigger ID. The Twig template renders deterministic IDs from the required group id and each item's explicit id, or from its one-based position when no item ID is provided.

aria-expanded follows the current state. Closed panels use the native hidden property rather than aria-hidden. On close, focus inside the panel returns to the trigger, the panel becomes inert while leave transitions run, and it becomes hidden when they finish; inert is then removed. On open, hidden and inert are removed before enter transitions run.

Nesting and dynamic children ​

A disclosure registers with its closest mounted DisclosureGroup. Children and groups may mount in either order; dynamically mounted children register themselves, removed children unregister, and a mounted disclosure reconnects when it is moved in the DOM. If a nearer nested group mounts later, the disclosure migrates to it. Public items and openItems are always returned in current DOM order.

Transitions belonging to a nested disclosure are not orchestrated by an outer disclosure.