Skip to content
exercises
HTML / CSS

Pure-CSS accordion

No JS. <details> is underused.

IntermediateSelf

An accordion component — expandable sections that reveal content when clicked — built entirely in CSS using the native <details> and <summary> elements.

The Challenge

Build an accordion where clicking a section header reveals the section body. Only one section should be open at a time. No JavaScript.

The native solution: <details> elements are interactive by default. The browser handles open/close state with no JS required.

The Implementation

<details class="accordion-item">
<summary class="accordion-header">What is this?</summary>
<div class="accordion-body">
<p>Content that reveals when the header is clicked.</p>
</div>
</details>

The <details> element manages its own open/closed state. Add the open attribute to start open. Remove it to start closed.

Styling the Arrow

The default triangle marker on <summary> can be replaced:

summary {
list-style: none;
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
}
summary::after {
content: "+";
transition: transform 0.2s;
}
details[open] summary::after {
transform: rotate(45deg);
}

Animated Open

Animating the expand is the tricky part — you can’t animate height: auto in CSS. One approach:

.accordion-body {
overflow: hidden;
max-height: 0;
transition: max-height 0.3s ease;
}
details[open] .accordion-body {
max-height: 500px;
}

This works but the closing animation is abrupt. The @starting-style rule (newly supported) solves this properly, but <details> + CSS alone gets you 90% there.

Why It Matters

The <details> element is semantically correct for disclosure patterns. It’s accessible by default — keyboard navigable, announced correctly by screen readers — which a DIV-based implementation requires extra ARIA to replicate.