<details> and <summary>
By cferdinandi for Semantic Advent |
π Hi, I'm Chris Ferdinandi, the vanilla JS guy.
Today, I wanted to teach you about two of my favorite HTML elements, <details>
and <summary>
. They provide a simple, JavaScript-free way to make interactive disclosure (or show/hide) components.
Let's dig in!
The basics
You put your entire disclosure content inside a <details>
element. The text that should act as a toggle goes inside a nested <summary>
element.
<details>
<summary>Toggle me</summary>
<p>Now you see me, now you don't!</p>
</details>
That's literally all you need to add an interactive show/hide component using just HTML. But, you can do so much more with it!
Default visibility
When the contents of a <details>
element are visible, it receives the [open]
attribute.
If you want to make your content visible by default, add the [open]
attribute to your starting markup.
<details open>
<summary>Toggle me</summary>
<p>I'm visible by default. Clicking "Toggle me" will hide me.</p>
</details>
Styling
You can style the <details>
and <summary>
elements just like any other HTML elements.
I personally like to give the <summary>
a bit more font weight, but you could also adjust the size, typeface, and so on. I also like to give it a cursor
to indicate to mouse users that it's interactive.
summary {
font-weight: bold;
cursor: pointer;
}
To style the expand/collapse icon, you can update the list-style-*
property on the summary
element for Firefox and Chromium browsers. For Webkit browsers, you'll instead need to use the ::-webkit-details-marker
pseudo-element.
Because HTML attributes are also styleable, you can hook into the [open]
attribute to do things like show a difficult icon when the content is expanded.
/**
* 1. Styling for Firefox and other non-webkit/blink browsers
* 2. Styling for webkit and blink
*/
summary, /* 1 */
summary::-webkit-details-marker { /* 2 */
list-style-type: '+ ';
}
/**
* 1. Styling for Firefox and other non-webkit/blink browsers
* 2. Styling for webkit and blink
*/
[open] > summary, /* 1 */
[open] > summary::-webkit-details-marker { /* 2 */
list-style-type: 'β ';
}
Toggle events
The <details>
element emits a toggle
event when its opened or closed. You can listen for this event with JavaScript to extend functionality beyond what's offered out-of-the-box.
let element = document.querySelector('details');
element.addEventListener('toggle', function (event) {
let isOpen = event.target.hasAttribute('open');
console.log('It was toggled', isOpen);
}, true);
The event does not bubble by default, so you'll need to pass in a value of true
for useCapture
in the addEventListener()
method if you want to detect events on all details
elements with one listener.
document.addEventListener('toggle', function (event) {
let element = event.target;
let isOpen = event.target.hasAttribute('open');
console.log('An element was toggled', element, isOpen);
}, true);
Here's a demo of listening to toggle
events.
You could use this to do stuff like load content asynchronously only after a <details>
element is opened, or turn a group of <details>
elements into an accordion group where only one element can be open at a time.
About Chris
Chris Ferdinandi helps people learn vanilla JavaScript, and believes thereβs a simpler, more resilient way to make things for the web. His developer tips newsletter is read by thousands of developers each weekday. Learn more at GoMakeThings.com.