Let's Play Accordion with the HTML details element
Managing content on a website can be challenging. You don't want to overwhelm your users with too much information at once. One helpful strategy is to place content in sections with show/hide functionality. A typical example would be an FAQ page with a list of expandable questions and answers.
We can use the native <details>
HTML element to create such a disclosure widget. The element has
been around for many years, but it used to be tricky to style and animate. Thanks to Interop 2025,
browsers have greatly improved their implementations of the element and added new features.
Photo: © Jefferson Lucena / pexels.com
I'll quickly go over the basics of the native HTML element. Then we'll take a look at the new shiny features. 🤩
The <details>
HTML element
The native details element creates a disclosure
widget, also called an expansion panel. The information placed inside the element is visible only when the widget is toggled into
an open state. We use the <summary>
HTML element to provide a label for the widget. Here's an
example:
<details>
<summary>An interesting question?</summary>
<p>A fascinating answer!</p>
</details>
With just a few lines of code we get a fully accessible disclosure widget. It communicates its name, role and current status to assistive technologies and is fully operable with a keyboard.
New Features
Exclusive Accordions with the name
attribute
An accordion component is a common UI pattern found on many websites. It consists of several disclosure widgets that individually can be expanded and collapsed.
A variation of the accordion pattern is the exclusive accordion, in which only one section can be open at
the same time. Use the name
attribute to turn a list of <details>
elements
into an exclusive accordion. Take a look at this code snippet from my CodePen demo:
<details name="faq">
<summary>What is the Doctor's real name?</summary>
<p>I'll never tell!</p>
</details>
<details name="faq">
<summary>Who are the Daleks?</summary>
<p>The Daleks are...</p>
</details>
Now the individual disclosure widgets are linked. When you open one of the sections in the accordion, the browser will automatically close all other sections. Try it yourself:
Content Styling with ::details-content
You can easily style the expandable content of the <details>
element using the
new ::details-content
CSS pseudo-element. Here's an example:
details::details-content {
color: rgb(54, 69, 79);
line-height: 1.3;
padding-inline: 0.5rem;
}
Furthermore, we can use the pseudo-element to animate the opening and closing of our disclosure widget. Our goal is to smoothly
transition the content from zero height to its full height. To pull this off, we depend on the still
experimental interpolate-size
CSS property, which is
only supported in Chromium browsers at the moment.
But don't worry! We can implement the animation as a progressive enhancement. Using the @supports
at-rule,
we only apply the animation when the browser supports it:
@supports (interpolate-size: allow-keywords) {
details {
interpolate-size: allow-keywords;
&::details-content {
height: 0;
overflow-y: clip;
transition:
height 0.35s ease,
content-visibility 0.35s ease allow-discrete;
}
}
details[open]::details-content {
height: auto;
}
}
I know, there's a lot going on in the CSS code above. I'll explain it step-by-step:
- By default, browsers don't support animations and transitions involving an intrinsic size value like
auto
. We enable this behavior by settinginterpolate-size: allow-keywords
. - We set the initial height of the content to zero (
height: 0
) and clip any overflowing content. - Using the
transition
shorthand, we define the animation of theheight
property. We also need to include thecontent-visibility
property, which is automatically set by the browser when the details element is expanded or collapsed. See transition-behavior for more information. - At last, we set
height: auto
for the content when the details element is in the open state.
Open my CodePen demo in Chrome or Edge to see the smooth animations for yourself. 😎
Custom Indicator for open/closed state
Browsers typically present the <details>
element with a small triangle that rotates to indicate
open/closed state. This indicator will appear differently across platforms and browsers.
To replace the default triangle with a custom indicator, we need to override the display: list-item
value of the <summary>
element. I use flexbox as this supports my desired layout. But you could also
set display: block
, for example.
In addition, we also need to hide the pseudo-elements for the default triangle. This
includes ::-webkit-details-marker
, which is used in the Safari browser:
details summary {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
&::marker,
&::-webkit-details-marker {
display: none;
}
}
Next, we define our custom indicator. I want to display an arrow icon that points downwards when the disclosure widget is closed.
Thanks to modern CSS, we don't need any images or icon fonts. We can simply draw the shape using the ::after
pseudo-element and the clip-path
CSS property.
details summary::after {
--shape-chevron-width: 1rem;
--s: calc(var(--shape-chevron-width) / 4);
content: "";
aspect-ratio: 7/5;
background: currentColor;
clip-path: polygon(0 0, 0 var(--s), 50% 100%, 100% var(--s), 100% 0, 50% calc(100% - var(--s)));
flex-shrink: 0;
width: var(--shape-chevron-width);
}
I adapted a code example from the website CSS Shape. It offers tons of code snippets for pure CSS shapes made with a single-element and modern CSS. You should definitely check it out! 🥰
Finally, we want the arrow icon to point upwards when the disclosure widget is open. Of course, the transition should be animated. Here's the code:
details {
summary::after {
rotate: 0deg;
transition: rotate 0.35s ease;
}
&[open] summary::after {
rotate: -180deg;
}
}
Et voilà! We've replaced the default triangle with a custom arrow icon that looks the same on all platforms and browsers. Here's the final result:
Flexbox and Grid Layouts
Historically it wasn't possible to change the display type of the <details>
element. This restriction
has now been relaxed in all major browsers (e.g., Firefox 143).
That means, it's finally possible to use grid or flex layouts on the <details>
element. Check out the
article “More options for styling <details>” on the Chrome Developer blog.
Conclusion
The <details>
and <summary>
elements are awesome! Thanks to the new
features we can easily create disclosure widgets and even exclusive accordions with custom styling and animations.
This means: One more type of content we can build with native web features. No need for UI library components and their annoying tendency for breaking changes. I love the (native) web! ❤️
Posted on