|$ curl https://forge-ai.dev/api/markdown?path=docs/html/details
$cat docs/details/summary-element.md
updated This week·28 min read·published

Details/Summary Element

HTMLDetailsSummaryInteractiveIntermediateIntermediate🎯Free Tools
Introduction

The <details> and <summary> elements create a native disclosure widget — click (or keyboard-activate) a heading to reveal or hide related content. No JavaScript is required for the core expand/collapse behavior, which makes details ideal for FAQs, progressive disclosure, and simple navigation menus.

Unlike custom accordion components built from buttons and aria-expanded, the browser wires up keyboard support, accessibility mappings, and the open/closed state for you. Modern HTML also adds a name attribute so a group of details behaves like an exclusive accordion — opening one closes others with the same name.

This guide covers anatomy, the open attribute, the toggle event, exclusive name grouping, nesting, marker styling, [open] selectors, FAQ and nav patterns, accessibility, when not to use details, comparisons with dialog/popover, JS enhancement, CSS-only tricks, browser quirks, and best practices.

info

Reach for <details> when content is optionally interesting — not when every panel must be equally discoverable as primary navigation tabs. Match the pattern to the information architecture.
Anatomy: details + summary

A disclosure widget has two parts. <details> wraps everything. Its first meaningful interactive child should be <summary> — the always-visible label users activate. Everything after the summary is the disclosure content, hidden until open.

details-anatomy.html
HTML
1<details>
2 <summary>Shipping policy</summary>
3 <p>Orders ship within 2 business days.</p>
4 <ul>
5 <li>Standard: 5–7 days</li>
6 <li>Express: 2–3 days</li>
7 </ul>
8</details>

If you omit <summary>, browsers invent a default label (often “Details”). Always provide an explicit, descriptive summary.

preview
The open Attribute

Add the boolean open attribute to render the widget expanded on first paint. Removing it (or setting details.open = false in JS) collapses the content. The attribute reflects live state as the user toggles.

details-open.html
HTML
1<!-- Expanded by default -->
2<details open>
3 <summary>Getting started</summary>
4 <p>Install the CLI, then run <code>init</code>.</p>
5</details>
6
7<!-- Collapsed by default -->
8<details>
9 <summary>Advanced configuration</summary>
10 <p>Override defaults in <code>config.json</code>.</p>
11</details>

best practice

Open the first FAQ item or the section matching the current page by default. Avoid opening every details on load — that defeats progressive disclosure and hurts scanability.
The toggle Event

Whenever a details element opens or closes, it fires a toggle event (after the state changes). Listen to sync analytics, lazy-load content, or update adjacent UI. Check event.newState in supporting browsers, or read details.open.

details-toggle.js
JavaScript
1const panel = document.querySelector("#faq-1");
2
3panel.addEventListener("toggle", (event) => {
4 // Modern: event.newState === "open" | "closed"
5 const isOpen = panel.open;
6 if (isOpen) {
7 console.log("Opened", panel.id);
8 // e.g. lazy-load a chart inside the panel
9 }
10});
📝

note

toggle does not fire for the initial open attribute on page load — only for subsequent user/script changes. Initialize any dependent UI separately on DOMContentLoaded if needed.
name Attribute — Exclusive Accordion

Modern browsers support name on <details>. Details that share the same name form an exclusive accordion group: opening one closes the others. No JavaScript required.

details-name-accordion.html
HTML
1<details name="pricing" open>
2 <summary>Hobby</summary>
3 <p>Free for personal projects.</p>
4</details>
5
6<details name="pricing">
7 <summary>Pro</summary>
8 <p>Team features and priority support.</p>
9</details>
10
11<details name="pricing">
12 <summary>Enterprise</summary>
13 <p>SSO, audit logs, and SLAs.</p>
14</details>
preview

warning

Exclusive name grouping is relatively new. Feature-detect or progressively enhance with a tiny script that closes siblings on toggle if you must support older browsers.
Nested Details

You can nest details inside details for hierarchical disclosure (docs outlines, file trees, nested FAQs). Keep nesting shallow — two levels is usually enough. Deep nesting becomes hard to navigate with a keyboard and visually noisy.

details-nested.html
HTML
1<details open>
2 <summary>API reference</summary>
3 <details>
4 <summary>Authentication</summary>
5 <p>Send a Bearer token in the Authorization header.</p>
6 </details>
7 <details>
8 <summary>Rate limits</summary>
9 <p>1000 requests per hour on the free plan.</p>
10 </details>
11</details>
Styling ::marker / summary::-webkit-details-marker

Browsers show a disclosure triangle next to the summary. Style it with summary::marker (standard) and hide the legacy WebKit pseudo-element when customizing. Many designs set list-style: none on summary and draw a custom indicator with ::before.

details-marker.css
CSS
1summary {
2 cursor: pointer;
3 list-style: none; /* hide default marker in supporting browsers */
4}
5
6summary::-webkit-details-marker {
7 display: none; /* Safari / older Chromium */
8}
9
10summary::marker {
11 content: ""; /* belt-and-suspenders */
12}
13
14summary::before {
15 content: "▸";
16 display: inline-block;
17 margin-right: 0.5rem;
18 color: #00ff41;
19 transition: transform 150ms ease;
20}
21
22details[open] > summary::before {
23 transform: rotate(90deg);
24}
🔥

pro tip

Prefer rotating a custom chevron over replacing the entire summary with a button. Keep the real <summary> as the interactive control so accessibility stays intact.
[open] Selectors

The [open] attribute selector is the primary hook for open-state styling. Style the summary differently when expanded, animate content height carefully (details height animation is historically tricky), and emphasize the active panel in a group.

details-open-selectors.css
CSS
1details {
2 border: 1px solid #222;
3 border-radius: 8px;
4 background: #0d0d0d;
5}
6
7details[open] {
8 border-color: #00ff41;
9}
10
11details[open] > summary {
12 color: #00ff41;
13 border-bottom: 1px solid #222;
14}
15
16details[open] > *:not(summary) {
17 animation: fade-in 160ms ease;
18}
19
20@keyframes fade-in {
21 from { opacity: 0; transform: translateY(-4px); }
22 to { opacity: 1; transform: none; }
23}
Details as FAQ

FAQs are the most common details use case. Use a heading level around the group, keep each summary a concise question, and put the answer in flowing content after the summary. For SEO, ensure answers are in the HTML (not loaded only after click via empty shells) so crawlers can index them — details content is in the DOM even when collapsed.

details-faq.html
HTML
1<section aria-labelledby="faq-heading">
2 <h2 id="faq-heading">Frequently asked questions</h2>
3
4 <details name="faq">
5 <summary>Do I need JavaScript for details?</summary>
6 <p>No. Expand/collapse works with HTML alone.</p>
7 </details>
8
9 <details name="faq">
10 <summary>Are answers indexed by search engines?</summary>
11 <p>Yes — collapsed details content remains in the document.</p>
12 </details>
13
14 <details name="faq">
15 <summary>Can multiple panels be open?</summary>
16 <p>Yes, unless they share a <code>name</code> for exclusivity.</p>
17 </details>
18</section>
Accessibility Considerations

Summary is keyboard-activatable (Enter / Space in supporting browsers). Screen readers expose the disclosure as an expandable widget. Keep summary text clear; do not nest interactive elements (links, buttons) inside the summary — that creates competing activation targets and confusing announcements.

DoDon't
Use a short, descriptive summaryPut buttons/links inside summary
Ensure visible focus stylesRemove outline without a replacement
Keep related content after summaryMove content with CSS order hacks that break SR reading
Test with keyboard onlyAssume click-only users
Use headings for the FAQ sectionFake headings with styled divs in summary only

best practice

If your design needs a chevron button separate from the title text, rethink the layout — summary should remain the single interactive disclosure control.
When NOT to Use Details

Details is a disclosure widget, not a universal tabs/accordion replacement for every IA pattern. Prefer dedicated tab patterns (role="tablist") when panels are peer views of equal importance and users switch frequently without a “summary vs body” mental model. Prefer dialogs for modal tasks, and popovers for ephemeral menus.

Complex tab UIs

Settings pages with many peer panels, dashboards with persistent panel chrome, and keyboard roving tabindex expectations belong to a proper tabs pattern — not nested details.

Primary app navigation on desktop

Always-visible nav is often better for wayfinding. Use details for overflow sections or mobile collapse, not as the only IA.

Content that must animate height precisely

Smooth height transitions on details are historically inconsistent. If motion design is a hard requirement, measure carefully or use a JS-enhanced accordion with explicit height animation.

Comparison with Dialog / Popover
NeedUseWhy
Inline expand/collapse<details>In-flow disclosure, no overlay
Modal confirm / form<dialog>Focus trap, backdrop, returnValue
Dropdown menu / tooltippopoverTop layer + light dismiss
Exclusive FAQ accordiondetails nameNative exclusive group
Peer tab panelsTabs patternEqual-weight views, arrow-key UX
JavaScript Enhancement

Start with HTML-only details, then enhance. Common enhancements: exclusive accordion polyfill, deep-linking (#faq-shipping opens a panel), analytics on toggle, and lazy-rendering heavy content the first time a panel opens.

details-enhance.js
JavaScript
1// Exclusive accordion polyfill when name is unsupported
2function enhanceExclusiveAccordions(groupName) {
3 const items = [...document.querySelectorAll(`details[name="${groupName}"]`)];
4 items.forEach((item) => {
5 item.addEventListener("toggle", () => {
6 if (!item.open) return;
7 items.forEach((other) => {
8 if (other !== item) other.open = false;
9 });
10 });
11 });
12}
13
14// Deep-link: /faq#shipping opens that panel
15const id = location.hash.slice(1);
16if (id) {
17 const target = document.getElementById(id);
18 if (target?.tagName === "DETAILS") target.open = true;
19}
CSS-Only Tricks

Beyond markers, you can swap summary labels with ::after content, grid-align chevrons, and use details[open] summary ~ * to style disclosed siblings. Avoid relying on display: none overrides that fight the UA — let the element manage visibility.

details-css-tricks.css
CSS
1/* Push chevron to the end */
2summary {
3 display: flex;
4 align-items: center;
5 justify-content: space-between;
6 gap: 1rem;
7}
8
9summary::after {
10 content: "Expand";
11 font-size: 0.75rem;
12 color: #525252;
13}
14
15details[open] > summary::after {
16 content: "Collapse";
17 color: #00ff41;
18}
Browser Quirks
QuirkImpactMitigation
Marker pseudo differencesInconsistent trianglesHide UA marker; use ::before
Height animationHard to animate openFade/slide content, or JS measure
name exclusivity supportMulti-open on old browsersSmall toggle polyfill
Summary + interactive childrenBroken activationNever nest links/buttons in summary
print stylesCollapsed content may hideForce open / display block in @media print
details-print.css
CSS
1@media print {
2 details {
3 open: true; /* not universally supported as property */
4 }
5 details,
6 details * {
7 display: block !important;
8 }
9 summary {
10 font-weight: 700;
11 }
12}
Best Practices

Write summary as a question or label

Users decide whether to expand based on the summary alone. Vague labels like “More” waste the pattern.

Keep default closed unless context demands open

Open the active nav section or the first FAQ when it helps orientation — not everything.

Prefer name for exclusive FAQs

Exclusive groups reduce scroll length and match user expectations for many FAQ UIs.

Enhance, don't reinvent

Start with native details. Add JS only for deep links, polyfills, or lazy loading.

Test print and find-in-page

Ensure critical content remains reachable when collapsed visuals differ across engines.

danger

Never use details as a substitute for proper headings structure across an entire page. A wall of summaries without section headings hurts screen reader navigation and SEO outline clarity.
FAQ
📝

note

Is details content in the accessibility tree when closed? Yes — but it is marked as collapsed/hidden depending on the browser and AT. Sighted users do not see it; crawlers still receive the HTML source.
📝

note

Can I put a form inside details? Yes. Forms work fine in disclosed content. Ensure validation errors expand the parent details if the invalid field is inside a closed panel.

info

How do I open all details for “expand all”? Query document.querySelectorAll('details') and set open = true. Provide a matching Collapse all control.

Community

Get help on Slack, Discord or VIP

Stuck on a guide? Join the community and ask.