Accordion
An animated, accessible panel that reveals or hides content when the user clicks its heading. Follows the controlled component pattern — the consumer manages open state.
When to use
Do
- ✓Use to organize large amounts of content in a structured, scannable way.
- ✓Group related content together within each panel.
- ✓Use clear, concise headings so users can quickly identify what is inside.
- ✓Choose a heading tag that fits the surrounding page outline (headingTag prop).
- ✓Use dense mode (compact) in sidebars, configuration panels, or data tables.
Don't
- ✕Don't hide content that is critical or required — users may not discover it.
- ✕Don't overuse accordions on a single page; too many create navigation fatigue.
- ✕Don't use ambiguous or vague headings — users must understand the content without expanding.
- ✕Don't overload individual panels with excessive content.
- ✕Don't add a manual divider above the first accordion — the component provides its own.
Controlled component pattern
diwa-accordion never mutates its own open prop. Instead it emits an update event with { open: boolean } representing the requested new state. The consumer must reflect that value back onto the open prop. This pattern gives the consumer full control: you can intercept, delay, or veto state transitions.
// Vanilla JS
const el = document.querySelector('diwa-accordion');
el.addEventListener('update', (e) => { el.open = e.detail.open; });
// React (JSX) — note lowercase onupdate for custom element event mapping
// See: https://react.dev/reference/react-dom/components/common#custom-html-elements
<diwa-accordion
heading="FAQ item"
open={isOpen}
onupdate={(e) => setIsOpen(e.detail.open)}
/>Exclusive group (accordion accordion)
To make only one panel open at a time, track a single active index and close all others when a panel is opened. Because each accordion is independent, this is entirely handled in user-land without any group container prop:
const [activeIndex, setActiveIndex] = useState<number | null>(null);
items.map((item, i) => (
<diwa-accordion
key={i}
heading={item.heading}
open={activeIndex === i}
onupdate={(e) => e.detail.open ? setActiveIndex(i) : setActiveIndex(null)}
>
{item.content}
</diwa-accordion>
))Heading tag
The headingTag prop wraps the toggle button in a semantic heading element. Set it to match the heading hierarchy at the point the accordion appears in the document. If the nearest ancestor section heading is h2, use headingTag="h3". The default is h2, which is appropriate for top-level FAQ or content sections.
Dense mode (compact)
The compact prop enables dense mode and reduces header padding from 20px 0 to 4px 0 and the font from the lg to base scale. Use it in space-constrained contexts such as sidebars, inspection panels, or nested accordion groups.