<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.

	<summary>Toggle me</summary>
	<p>Now you see me, now you don't!</p>

Here's a demo.

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>

Here's another demo.


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: '– ';

Here's a demo with styling.

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.

Sign up and receive byte-sized emails about Semantic HTML Elements this advent with real-world use cases!