Simplifying accordions with the details disclosure element
Stuart Harland
23 January 2025
Last year, I wrote about how to create a simple, accessible accordion using traditional HTML, CSS, and JavaScript techniques. This is a follow-up that explores a built-in alternative - the <details> element.
Now, the <details> tag isn’t exactly brand new - it’s been around since early 2020, and browser support has come a long way since then. The beauty of it is that it lets you create an accordion-like effect without lots of code.
So, in this post, I’ll walk you through how the <details> element works, but more importantly, I’ll show you how to style it and add some smooth transitions. The goal? To give you a clean, user-friendly accordion that looks and feels like the traditional example in my other article, but with much less work.
Background
Let’s face it - there are loads of ways to build accordions out there, and it can be a bit much trying to figure out the ‘right’ approach, especially when you’re keeping accessibility in mind. But there is an easier option.
Meet the <details> element. It’s a built-in part of HTML that gives you a simple, lightweight, and accessible way to create collapsible content. No JavaScript required. Plus, you don’t have to stress about whether your mark-up makes sense or if everyone can actually use the thing. It works pretty well!
Using it is amazingly straightforward. The <details> element acts as a wrapper for your collapsible content, and inside it, you’ll add a <summary> element. The <summary> acts as a clickable heading that toggles the content open and closed. Everything else you put inside <details> stays hidden until the user interacts with it.
Here’s a quick example to show you how it’s structured:
<details>
<summary>View the details on my topic</summary>
<p>This is the content that will be shown when the accordion is expanded.</p>
<p>So will this content....</p>
</details>
And just like that, you’ve got a working piece of collapsible content. Click the summary heading, and we have open and close functionality, all without a single line of JavaScript. Pretty cool!
Notable attributes
openattribute – This controls whether the<details>content is visible or hidden. If the attribute is added, the content is displayed by default. If not, the content stays hidden until someone interacts with it.nameattribute – Thenameattribute lets you group multiple<details>elements together, giving you a handy “only one section open at a time” accordion behaviour. These grouped elements don’t even need to be next to each other in the code, and they’ll still work together.
Accessibility and more
One of the best things about <details> is that it’s a standard, built-in HTML tag. That means it’s widely recognised and works pretty well with screen readers and keyboard navigation right out-of-the-box. If you’re looking for an accessible option for collapsible content in your next project, this could be a good choice. Let’s go over some of the accessibility benefits and things to watch out for:
-
Keyboard navigation: Keyboard users can tab through interactive elements inside the
<details>and useEnterorSpaceto toggle the<summary>open and closed. It’s intuitive and doesn’t require extra scripting. -
ARIA support: Modern browsers will handle ARIA roles and states for you, like aria-expanded, so there’s no need to manually add these with JavaScript. The
<details>element already has an implicit group role, so adding one yourself isn’t necessary. You can find more information on ARIA: group role here. -
Custom tailoring: While
<details>works great as-is, you can easily add a bit of polish with CSS. Things like hover and focus states, custom cursor styling, or additional visual cues can go a long way in improving usability and accessibility. -
Make sure to test: Not all browsers or assistive technologies handle
<details>exactly the same way, so don’t skip the testing phase. Make sure it behaves consistently across the tools your audience might be using. -
What about SEO?: Even though the content inside
<details>is hidden by default, search engines can still crawl and index it. You don’t have to jump through any extra hoops to make it SEO-friendly.
Changing the look
So, onto a bit of styling, because to be honest, the default <details> look is pretty bare-bones and isn’t exactly going to win any design awards. It’s super easy to style up and make it look more like the classic accordions I covered in my earlier article.
Demo HTML:
<details>
<summary>Accordion Item 1 <span aria-hidden="true" class="icon-arrow"></span></summary>
<div class="content">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla vitae eros eu nulla venenatis malesuada.</p>
<p>Reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</p>
</div>
</details>
Here’s what I’m adding in styling:
- The
<details>element - I’ll add a solid border, rounded corners, making it look neater and like a self-contained component. I also hide any overflowing content (explained later.) - The
<summary>element will be styled as a clickable button. I’ll use flex with space-between to separate my text and a demo arrow icon (using as an added visual cue). Then it’ll be standard styling - a nice bold font, a warm background colour, and smooth hover/focus effects. - When the
<details>element isopen, the<summary>background will subtly change, and the arrow icon will rotate to futher indicate the open state, and act as a wee cue that it can be closed again. - In my HTML I’ve wrapped all my inner content in a
.contentdiv - this really acts as a nice way for me to target and provide styling for the elements I might to show. I’ll just quickly use flex to space out some paragraphs, but you’ll get the idea. - If there are multiple
<details>elements stacked,margin-block-startis used to separate them nicely.
Demo CSS:
details {
border: 2px solid #333;
border-radius: 0.375rem;
background-color: #fff;
/* make the summary look more like a simple button with pointer cursor */
summary {
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
text-align: left;
font-size: 1.125rem;
font-weight: 700;
gap: 0.938rem;
padding: 0.938rem;
background-color: #fdf7ed;
color: #363636;
transition: background-color 0.3s, color 0.3s;
font-family: 'Inter', sans-serif;
/* add your pseudo-classes and styling for interation */
&:hover,
&:focus-visible {
background-color: #f7e4d9;
}
/* just a small demo icon as a visual cue */
.icon-arrow {
display: block;
height: 24px;
width: 24px;
background-position: center;
background-size: contain;
background-image: url('data:image/svg+xml,<svg height="48" viewBox="0 0 48 48" width="48" xmlns="http://www.w3.org/2000/svg"><path d="M14.83 16.42l9.17 9.17 9.17-9.17 2.83 2.83-12 12-12-12z"/><path d="M0-.75h48v48h-48z" fill="none"/></svg>');
transition: rotate 0.3s;
}
}
/* using a div to group and handle inner content styling */
.content {
padding: 1.25rem;
background-color: #fff;
display: flex;
flex-direction: column;
gap: 0.938rem;
* {
margin-bottom: 0;
}
}
/* add some nice spacing to adjacent details blocks */
+ details {
margin-block-start: 0.9375rem;
}
/* when the details are open, set a colour on summary, and rotate the icon */
&[open] summary {
background-color: #f7e4d9;
.icon-arrow {
rotate: 180deg;
}
}
/* simple element styling */
p {
font-size: 1rem;
font-weight: 400;
line-height: 1.4;
font-family: 'Inter', sans-serif;
}
}
The styling result
A smoother experience
To enhance the user experience, we can add CSS animations to create a smooth open and close effect, but before we dive in, we have to address an issue first - luckily, it’s something browsers are getting better at handling.
When you’re animating certain CSS properties - especially ones with discrete values like visibility or display, it has always been a bit challenging for browsers. These properties can’t be gradually animated over like numeric ones (e.g., opacity or height). Instead, they just flip from one state to another, which isn’t exactly smooth or elegant. No one likes clunky animations.
Thankfully, newer CSS features let us work around this. Without them, your browser would just skip the transition entirely and the state would just toggle - not the experience we’re going for.
Now, I’ve got to give credit where it’s due: everything I’m about to share comes from the ultimate CSS wizard, Kevin Powell. If you’re into CSS and haven’t checked out Kevin’s YouTube channel yet, you’re seriously missing out.
The channel is jam packed with videos are full of new approaches, experiments, and amazing tips and tricks, and the content is always amazingly fun and super informative. I’ve added links to Kevin’s channel and the video on styling the <details> element at the end of this article.
CSS additions
:root {
interpolate-size: allow-keywords;
}
details {
overflow: hidden;
&::details-content {
block-size: 0;
transition: block-size 0.3s, content-visibility 0.3s;
transition-behavior: allow-discrete;
}
&[open]::details-content {
block-size: auto;
}
}
Breaking down the CSS
Let’s unpack what’s going on with this extra CSS and how it all comes together to create that polished, smooth animation.
-
interpolate-size: allow-keywords;: This addition to the :root selector gives us control over whether animations and transitions involving CSS intrinsic sizing keywords (like auto) are allowed. Put plainly, it tells the browser, “try to animate size changes like block-size: 0 to block-size: auto instead of just snapping between them.” Browser support for this is still a little limited, but it’s great for progressive enhancement. For browsers that can handle it, you’ll get a smooth, flowing animation instead of a jarring switch. View allow-keywords on ‘Can I Use’.
-
::details-content a shadow DOM pseudo-element: This targets the collapsible content inside the
<details>element. Initially, its height (using block-size) is set to 0, which keeps it completely hidden. -
When the
<details>element is toggled open, the ::details-content automatically expands to fit its content using block-size: auto. This reveals the hidden section smoothly, without any abrupt state “flip” or jump. -
The transition-behavior: allow-discrete; property allows the nice transition effect to both the height and visibility of the content. It’s a game-changer because it lets discrete properties - like visibility, content, or display - animate instead of just flipping states instantly. This gives us much smoother, more polished animation.
-
content-visibility 0.3s; - this property in the transition attribute gives us to have a smooth transition when closing the
<details>section, not just when opening it. -
overflow: hidden; - this simply hides any content that overflows while the
detailis collapsing or expanding.
Why This Matters
These small tweaks make a big difference, and don’t jeopardise use of details on browsers that do not yet support these attributes and properties. The animation feels smooth and natural, and the interaction is more polished.
Conclusion
Using the <details> element is a simple, accessible, and effective way to add accordions to your projects. It’s a built-in solution that keeps your code lean, relying on just a bit of HTML and CSS. And no need to over-complicate things, this approach is perfect if you want to keep your code clean while still prioritising accessibility.
So, next time you’re putting together an accordion, consider reaching for these handy HTML elements and keep things clean and efficient.
Further reading & resources
- Details element information at MDN
- Details element information at web.dev
- Kevin Powell’s amazing video on animating the Details element
- Kevin Powell’s YouTube channel
- interpolate-size information at MDN
- details-content pseudo element information at MDN
- allow-discrete information at MDN