HTML Details Element
Some content is helpful, but not everyone needs it all at once: a list of frequently asked questions, the technical details of a product, a long set of terms, a spoiler. You want to tuck it away so the page stays calm, and let people open it when they want it.
For years, that meant writing JavaScript. Today HTML does it by itself with the <details> element. It is a small, built-in disclosure widget: a heading you can click to reveal more. It works with the mouse, the keyboard, and screen readers, and needs no script at all.
What You Will Learnβ
- What
<details>is and how its parts fit together - Starting open with the
openattribute - Exclusive accordions with the
nameattribute - Reacting in JavaScript: the
openproperty and thetoggleevent - Styling the marker and the box
- Good and bad uses
- Accessibility, printing, search, and security notes
- Common mistakes
The Basicsβ
<details> contains one <summary> (the always-visible label), followed by the hidden content.
- HTML Code
- Browser Output
<details>
<summary>Can I bring my own apron?</summary>
<p>Yes. Aprons are welcome, and spares are available at the desk.</p>
</details>
details {
border: 1px solid #cbd5e1;
border-radius: 6px;
padding: 0.5rem 0.75rem;
}
summary {
cursor: pointer;
font-weight: 600;
}
Can I bring my own apron?
Yes. Aprons are welcome, and spares are available at the desk.
Click the summary. The content appears, and a small triangle (the marker) turns to show the open state. Click again to close it. Nobody wrote a line of JavaScript.
The two parts:
| Part | Role |
|---|---|
<summary> | The visible label that is always shown. It must be the first child of <details>. See Summary |
| Everything else | The hidden content, shown when the widget is open |
If you leave out the <summary>, the browser supplies a default label such as "Details". Always write your own.
Starting Openβ
The boolean attribute open makes the widget start expanded:
<details open>
<summary>Opening times</summary>
<p>Saturday and Sunday, 9:00 to 18:00.</p>
</details>
The browser adds and removes the open attribute itself as the visitor clicks. In JavaScript, you can read or set it:
const box = document.querySelector("details");
console.log(box.open); // true or false
box.open = true; // expand it
box.open = false; // collapse it
Try It: Several Questions at Onceβ
This FAQ uses independent <details> items. Use the buttons to open and close them all with the open property, and watch the toggle event fire.
- HTML Code
- Browser Output
<button type="button" id="open-all">Open all</button>
<button type="button" id="close-all">Close all</button>
<details>
<summary>Can I bring my own apron?</summary>
<p>Yes. Aprons are welcome, and spares are available at the desk.</p>
</details>
<details>
<summary>Is there parking?</summary>
<p>Limited parking is behind the town hall.</p>
</details>
<details>
<summary>Are there gluten-free options?</summary>
<p>Several stalls offer gluten-free bread. Look for the green label.</p>
</details>
const items = document.querySelectorAll("details");
document.getElementById("open-all").addEventListener("click", () => {
items.forEach((item) => (item.open = true));
});
document.getElementById("close-all").addEventListener("click", () => {
items.forEach((item) => (item.open = false));
});
// The toggle event fires after the widget opens or closes
items.forEach((item) => {
item.addEventListener("toggle", () => {
const label = item.querySelector("summary").textContent;
console.log((item.open ? "opened: " : "closed: ") + label);
});
});
Can I bring my own apron?
Yes. Aprons are welcome, and spares are available at the desk.
Is there parking?
Limited parking is behind the town hall. Cycling or walking is easier on busy days.
Are there gluten-free options?
Several stalls offer gluten-free bread. Look for the green label.
Toggle events:
- Nothing yet. Open or close an item.
Two details of the toggle event:
- It fires after the state changes, for clicks, for keyboard use, and when your script changes
open. - It does not bubble, so listen on each
<details>element, not on a parent. (In frameworks, use the event the framework provides, such asonTogglein React.)
Exclusive Accordions: the name Attributeβ
Sometimes you want only one item open at a time, like an accordion. Give several <details> elements the same name:
- HTML Code
- Browser Output
<details name="steps" open>
<summary>Step 1: Mix</summary>
<p>Combine flour, water, salt, and yeast.</p>
</details>
<details name="steps">
<summary>Step 2: Knead</summary>
<p>Knead for ten minutes until smooth and elastic.</p>
</details>
<details name="steps">
<summary>Step 3: Rest</summary>
<p>Cover and rest until doubled in size.</p>
</details>
These three share the same name. In current browsers, opening one closes the others.
Step 1: Mix
Combine flour, water, salt, and yeast.
Step 2: Knead
Knead for ten minutes until smooth and elastic.
Step 3: Rest
Cover and rest until doubled in size.
Opening one now closes the other members of the group. This works in current versions of the major browsers. In an older browser that does not know name, the items simply behave as independent widgets, so nothing breaks, and the page still works. That is a good example of progressive enhancement.
Rules for the group:
- Items with the same
namein the same page form one group. - Use
openon at most one of them at the start. - It is the browser's job, so you do not need any JavaScript for it.
A group that closes the others hides what the visitor just read, and makes it hard to compare two answers. Use the exclusive style for sequential content such as steps, and independent items for FAQs.
Good Usesβ
| Good use | Why it works |
|---|---|
| FAQ lists | Visitors scan the questions and open only what they need |
| Extra technical detail ("Full specifications") | Keeps the main page short |
| Long legal text or terms you must show but few will read | Out of the way, still available |
| Step-by-step help with optional hints | Reveal a hint only when asked |
| Spoilers and answers to quiz questions | The visitor decides when to look |
| Optional advanced settings in a form | Keeps the simple path simple |
| Code or log output that is long | Shows the heading, hides the wall of text |
Bad Uses (Use Something Else)β
Do not use <details> for | Use instead |
|---|---|
| A navigation menu or dropdown of links | <nav> with a button using aria-expanded (see Nav) |
| Tabs | A proper tabs pattern, or separate sections |
| A pop-up or modal that blocks the page | <dialog> |
| A tooltip | aria-describedby and a visible hint |
| Essential information the visitor must see (errors, warnings, prices, the main message) | Show it in the open |
| A list of things people compare often | A table or a plain list |
| Hiding content for security | Access control on the server |
Stylingβ
The default look is plain: a triangle and a label. You can change a lot with CSS:
details {
border: 1px solid #cbd5e1;
border-radius: 8px;
padding: 0.5rem 0.75rem;
}
/* Style the box when it is open */
details[open] {
background: #f8fafc;
}
summary {
cursor: pointer;
font-weight: 600;
padding-block: 0.25rem;
}
/* Replace the default triangle */
summary {
list-style: none;
}
summary::-webkit-details-marker {
display: none; /* older WebKit browsers */
}
summary::before {
content: "+";
display: inline-block;
width: 1.25rem;
font-weight: 700;
}
details[open] > summary::before {
content: "β";
}
/* A visible focus ring for keyboard users */
summary:focus-visible {
outline: 3px solid #1d4ed8;
outline-offset: 2px;
}
Some points:
- The built-in triangle is the marker (
summary::marker, orlist-styleon the summary). You can swap it for your own icon, but always keep a visible sign of whether the item is open or closed. - Do not remove the focus ring. Keyboard users need it.
- Very new browsers also let you style the hidden content with
details::details-contentand animate opening, but support is still growing. Test before you rely on it. - Do not hide the summary text with
display: none. A summary should always be visible.
How It Works for Assistive Technologyβ
- A
<details>is exposed as a group. Its summary acts like a button with an expanded or collapsed state, so a screen reader says something like "Can I bring my own apron? Collapsed, button". When opened, it says "expanded". - It is keyboard accessible by default. Tab moves focus to the summary, and Enter or Space opens and closes it.
- You do not need ARIA. Do not add
role="button"oraria-expandedto a<summary>, because the browser already does the right thing, and extra ARIA can conflict.
Printing, Searching, and Sharingβ
- Print: content inside a closed
<details>generally does not print. If the content matters on paper, open the items before printing (for example, with a small script on thebeforeprintevent), or provide a print version. - Find in page: some browsers can search inside closed
<details>and open the item to show the match. Others do not. Do not depend on it. - Search engines can generally read content in closed
<details>, but visitors may overlook it. Do not hide your most important content. - Links to an item: an
idon the<details>lets you link to it (#parking), but the browser will not open it for you in every case. You can open it with a small script when the hash matches.
function openFromHash() {
const target = document.querySelector(location.hash || "#none");
if (target && target.tagName === "DETAILS") target.open = true;
}
window.addEventListener("hashchange", openFromHash);
openFromHash();
Accessibility at a Glanceβ
- Use a clear, short summary that says what is inside. "Opening times" beats "Click here".
- Keep the summary text visible and in a good colour contrast (at least 4.5 to 1).
- Show an open and closed indicator that is not only colour.
- Keep a visible focus style on the summary.
- Do not put interactive elements (links, buttons, form fields) inside the summary. Put them in the content area.
- Do not hide essential content in a closed
<details>. - Do not nest too deeply. Two levels is the most most people can follow.
- Make tap targets big enough: padding on the summary gives at least 44 by 44 pixels where you can.
- Do not change focus or scroll unexpectedly when it opens.
- Test with a keyboard and a screen reader.
Security and Privacy Notesβ
- A closed
<details>hides content visually, not from the page. Anyone can open it, read the HTML source, or use developer tools. Never put secrets, private data, or "hidden" answers you need to protect in it. - Escape user-supplied text you place in a summary or its content, so it cannot inject markup or scripts.
- If you load content when the item opens (using the
toggleevent andfetch), request only what the visitor is allowed to see, and check permission on the server. - Do not store sensitive state (such as which items a user opened) in a place other people can read.
- Be careful with user-generated HTML inside
<details>. Sanitise it, as you would anywhere else.
Global Audience Notesβ
- Translate the summary text, and keep it short, since translated labels can be much longer.
- Right-to-left pages: the built-in marker moves to the right side automatically with
dir="rtl". If you draw your own marker with CSS, use logical properties (margin-inline-end) so it flips correctly. - Do not rely on the triangle alone to mean "open me". Some people may not recognise it, so keep the label clear.
- Long answers on small screens: FAQs are popular on phones. Keep the content short, and keep touch targets large.
- Slow or older devices work fine with
<details>, because it needs no JavaScript. - Legal text: if the law requires that visitors can see something (such as terms or consent details), check whether hiding it in a collapsed item meets the rule.
Common Mistakes to Avoidβ
- Forgetting the
<summary>, or putting it somewhere other than the first child. - A vague summary such as "More" or "Click here".
- Hiding essential information in a closed
<details>. - Using it for navigation menus, tabs, or modals.
- Removing the focus outline or the open and closed indicator.
- Putting links or buttons inside the
<summary>. - Adding
role="button"oraria-expandedto<summary>. - Expecting the
toggleevent to bubble. - Expecting closed content to print, or to be found by every browser's find-in-page.
- Using
namegroups without testing in the browsers you support. - Hiding secrets in a closed item.
- Nesting many levels deep.
Practice Timeβ
Try these in your editor:
- Build a
<details>with a<summary>and one paragraph. - Add the
openattribute, and compare how it loads. - Build an FAQ with five questions, using independent
<details>elements. - Add "Open all" and "Close all" buttons with JavaScript.
- Log a message with the
toggleevent each time an item opens or closes. - Make a three-step accordion where only one step stays open, using the
nameattribute. - Replace the default triangle with a "+" and "β" using CSS.
- Give the summary a clear focus ring, and test it with Tab, Enter, and Space.
- Open an item automatically when the page address has a matching
#id. - Bonus: open all items before printing, using the
beforeprintevent.
Quick Recapβ
Click a question to check your answer.
1. What does the <details> element do?
It creates a built-in disclosure widget: a visible <summary> label that the visitor can click, or activate with the keyboard, to show or hide extra content. It needs no JavaScript.
2. How do you make a <details> start open?
Add the boolean open attribute. The browser adds and removes it as the visitor interacts, and you can read or set it with the open property in JavaScript.
3. How do you make only one item open at a time?
Give several <details> elements the same name value. Opening one closes the others in current browsers. In older browsers, they just work independently.
4. How do you react when an item opens or closes?
Listen for the toggle event on the <details> element. It fires after the state changes, including changes made by script, and it does not bubble.
5. What should you not do with <details>?
Do not use it for navigation menus, tabs, or modals, do not hide essential information in it, do not put links or buttons in the summary, and do not rely on it to keep secrets.
6. Do you need ARIA on <details> and <summary>?
No. The browser already exposes the group, and the summary's expanded or collapsed state. Adding role="button" or aria-expanded can conflict with the built-in behaviour.
Key Takeawaysβ
<details>plus<summary>is a built-in, JavaScript-free disclosure widget, with keyboard and screen reader support.- The
<summary>is the first child and is always visible. Everything else is revealed when the item opens. - The
openattribute starts it expanded, and theopenproperty andtoggleevent let scripts work with it. - Give several items the same
namefor an exclusive accordion (current browsers), and they degrade to independent items elsewhere. - Great for FAQs, extra detail, and spoilers. Poor for navigation, tabs, modals, and essential content.
- Keep a visible marker and focus ring, write a clear summary, and never put links or buttons in it.
- Closed content may not print or be found by find-in-page, and it is not hidden from the page source, so it is never a place for secrets.
Next, learn more about the label of a disclosure widget, in Summary, or return to the Semantic HTML overview.