Accordion
A column of disclosures built on details and summary, each opening to show its panel, with the browser doing the opening, the keyboard, and the announcing.
Example
View Code
<div class="accordion">
<details name="faq">
<summary>Does Yeti need JavaScript?</summary>
<p>Almost never. A handful of optional modules exist and nothing depends on them.</p>
</details>
<details name="faq">
<summary>Can I use my own class names?</summary>
<p>Yes. Anything Yeti does not declare is ignored.</p>
</details>
</div>
When to use it
A run of questions and answers, a set of sections most readers only want one of, a long form split into stages. Not for content everyone needs: if it matters, leave it open.
How it works
Each panel is a details with a summary, so the opening, the keyboard, and the announced state come from the browser rather than from Yeti. The component draws the lines between panels, the padding, and a chevron that turns when the panel opens.
Each summary sits on its own surface, clearly apart from the answer below it, and moves a step further under the pointer. That is what keeps a set of rows reading as rows rather than as one undivided block; an open one also keeps a line under it. Three tokens carry it: --yeti-accordion-surface for the set and so for the panels, --yeti-accordion-summary for a row at rest, and --yeti-accordion-summary-hover for the one under the pointer.
The last two are mixed from the first toward the text colour rather than picked off the surface ramp, because the ramp's own steps are too small to read here. Mixing toward text also moves the right way by itself in both schemes, darkening the row on a light page and lifting it on a dark one, and a theme that restyles --yeti-color-surface or --yeti-color-text gets a header that still works without redefining anything.
The panel grows open rather than appearing. A details cannot animate its own height to auto in every engine, because the keywords that make auto interpolable are Chromium's alone, so the set makes each details a two-row grid instead: the summary takes the first row and the generated panel the second, and the transition runs on that row's size. That works in all three engines, and the panel clips its overflow so the content is revealed rather than squashed. The rows are packed to the start of the grid, because an fr row is a share of the leftover space and the summary would otherwise take part in that sum and visibly swell while the share was being interpolated.
Closing animates in Chromium and Firefox. WebKit shuts the panel at once, because it drops the panel's content before the row has anything left to shrink. Opening is smooth everywhere, which is the direction people watch.
Under prefers-reduced-motion the whole thing collapses with the rest of Yeti's motion, and the panel simply appears.
To open one at a time, give every details the same name. That is the browser's own exclusive accordion, and it needs nothing from Yeti. There is deliberately no Yeti attribute for it: CSS cannot set an attribute, so the only way to offer one would be a script, and this is a component that should never need one.
<div class="accordion">
<details name="plans" open>
<summary>Monthly</summary>
<p>Cancel whenever you like.</p>
</details>
<details name="plans">
<summary>Yearly</summary>
<p>Two months free.</p>
</details>
</div>
Accessibility
A summary is a button to assistive tech, and its panel's state is announced as it opens and closes, so nothing needs ARIA. summary is not a heading, so if the rows are section titles, put a heading element inside each one. Keep the summary's text meaningful on its own, since a reader may hear the rows in a list before choosing one.
Attributes
None. This is configured through its children and tokens only.
Children
> details: at least 2. One disclosure each. Give them all the same name attribute to have the browser close the others when one opens.summary: at least 2. The row that opens its panel; one per details, first inside it.
Tokens
| Token | Description |
|---|---|
--yeti-accordion-border |
The line between panels and around the set. |
--yeti-accordion-padding |
Padding of a summary and its panel. |
--yeti-accordion-surface |
Background of the set, and so of an open panel. |
--yeti-accordion-summary |
Background of a summary row, set apart from the panel below it. |
--yeti-accordion-summary-hover |
Background of a summary under the pointer. |
--yeti-border-width |
Width of those lines. |
--yeti-radius-md |
Corner of the set. |
--yeti-space-sm |
Gap between a summary's text and its chevron. |
--yeti-weight-strong |
Weight of the summary text. |
--yeti-duration-fast |
How long the chevron takes to turn. |
--yeti-ease |
The curve of both transitions. |
--yeti-duration-base |
How long a panel takes to open or close. |
Accessibility
- This is native: details is a disclosure, summary is its button, and the open state is the open attribute, all announced without help. Put a heading inside the summary if the row is a section title, since summary is not a heading by itself. To open one at a time, give every details the same name attribute, which is the browser's own exclusive accordion; Yeti adds no attribute for it, because CSS cannot set one and script should not be needed.
| Key | Action |
|---|---|
Tab |
Moves to the next summary. |
Enter / Space |
Opens or closes the panel under the focused summary. |
Browser support
- Used without guards: details name attribute, individual transform properties, overflow: clip, animating a grid row between 0fr and 1fr, discrete transition of content-visibility (where missing, the panel still grows open and shuts at once rather than shrinking)
- Behind
@supports: nothing
JavaScript
None. This component is CSS only.
Available since 7.0.0.