šŸš€ LEVEL UP TO SENIOR:Unlock 500+ Advanced Practical Challenges & Exercises.
šŸŽ“ COURSERA PARTNER:Earn professional Google, Meta, and IBM certificates to supercharge your resume.
HTML MASTER CLASS /// LEARN TAGS /// BUILD STRUCTURE /// SEMANTIC WEB /// HTML MASTER CLASS /// LEARN TAGS ///

Advanced <details> & <summary>: The Native Accordion, Fully Realized

Master the name attribute for exclusive accordion groups, the toggle and beforetoggle events, styling ::marker and animating open/close height with interpolate-size, and the nested-interactive-control accessibility pitfall.

⚔ Total XP: 0|šŸ’» html XP: 0

Skill Matrix

UNLOCK NODES BY LEARNING NEW TAGS.

Advanced Details/Summary

Native accordions.


šŸš€ LEVEL UP TO SENIOR:Unlock 500+ Advanced Practical Challenges & Exercises.
šŸŽ“ COURSERA PARTNER:Earn professional Google, Meta, and IBM certificates to supercharge your resume.

The basic disclosure widget is well known; what's less well known is that HTML now natively covers the entire accordion pattern — exclusive groups, state-change events, and real height-animatable open/close transitions — that used to require a JS component.

1Exclusive Accordions With The name Attribute

Giving several <details> elements the same name attribute value groups them into a mutually exclusive set — the browser guarantees that opening one automatically closes any others sharing that name, entirely as native behavior with zero JavaScript coordination. This directly replaces the previously-standard pattern of a shared JS array or object tracking which panel is currently open and manually toggling the rest closed on each click.

A page can have multiple independent named groups simultaneously — a FAQ accordion using name="faq" and an unrelated settings panel using name="settings" don't interact with each other at all, since grouping is scoped purely by matching name values, not by DOM proximity.

<details name="faq">
  <summary>Return policy?</summary>
  <p>30 days, no questions asked.</p>
</details>
<details name="faq">
  <summary>International shipping?</summary>
  <p>Yes, to 40+ countries.</p>
</details>
localhost:3000
āœ“ Zero-JS Exclusive Accordion BehaviorGrouping is scoped entirely by matching name values — independent groups don't interfere with each other.

2Reacting To State Changes: toggle And beforetoggle

The toggle event fires on a <details> element after its open state has changed, carrying newState and oldState properties reporting "open" or "closed" directly — a cleaner API than manually reading the .open boolean inside a generic event handler. The newer beforetoggle event fires just before the change and is cancelable, letting code prevent a state transition under specific conditions (for instance, blocking a panel from closing while an async operation inside it is still pending).

A common, genuinely useful pattern: listening for toggle and checking newState === "open" to lazy-load a panel's content only the first time a user actually expands it, rather than fetching or rendering content for every accordion item up front regardless of whether it's ever opened.

details.addEventListener("toggle", (e) => {
  if (e.newState === "open" && !loaded) {
    loadPanelContent();
    loaded = true;
  }
});
localhost:3000
āœ“ newState/oldState Beat Manual .open ChecksA direct, readable API for reacting to disclosure state transitions, including lazy-loading patterns.

3Restyling The Marker And Animating Real Height Transitions

The default disclosure triangle is the <summary> element's list marker, fully accessible through the standard ::marker pseudo-element — content can swap its glyph entirely (a +/āˆ’ pair, or a rotating chevron via a transform on a ::before alternative), matching exactly how markers are styled on ordinary list items.

Animating the actual expand/collapse *height* — not just a fade — has historically been the genuinely hard part, since height: auto isn't natively transitionable. The interpolate-size: allow-keywords CSS property changes that, enabling transitions between auto and a fixed height, finally making a smooth, JS-free accordion height animation achievable in pure CSS.

summary::marker { content: "ā–ø "; }
details[open] summary::marker { content: "ā–¾ "; }
details { interpolate-size: allow-keywords; }
.panel { height: 0; overflow: hidden; transition: height .25s; }
details[open] .panel { height: auto; }
localhost:3000
āœ“ Real Height Animation, Not Just Opacityinterpolate-size finally makes auto-height transitions possible without JS-measured pixel heights.

4Free Disclosure Semantics — And The One Real Pitfall To Avoid

<summary> behaves as a fully accessible disclosure button by default: keyboard-focusable, activatable with Enter or Space, and announced by assistive technology with an implicit expanded/collapsed state that updates automatically as <details> opens and closes — none of it requires manual role="button" or aria-expanded bookkeeping.

The one genuine trap is nesting another interactive element — a <button> or <a> — directly inside <summary>. Because <summary> is already an interactive control, this creates nested interactive controls, which is invalid HTML with inconsistent, browser- and AT-dependent behavior (some browsers may not correctly dispatch clicks to the inner control at all). If a summary genuinely needs an additional clickable action beyond toggling, that control belongs as a sibling inside the <details> body, not nested inside <summary> itself.

<!-- Correct -->
<summary>Order #4471</summary>
<a href="/orders/4471">View full order</a>
localhost:3000
āœ“ Disclosure Semantics: Free. Nested Controls: Avoid.Keep any additional interactive action as a sibling of , not nested inside it.

5Step-by-Step Breakdown

A Native Accordion, No JavaScript Required. A FAQ accordion where opening one question closes the others used to require JavaScript state management. The name attribute on <details> makes that grouping behavior entirely native — one more case of the platform absorbing what used to be a component library's job.

The name Attribute Creates Exclusive Accordion Groups. Giving multiple <details> elements the same name attribute value makes them mutually exclusive — opening one automatically closes the others in the group, exactly the accordion behavior developers previously built by hand with a shared JS state object and manual open/close toggling.

The name Attribute. What happens when two <details> elements share the same name attribute value?

  • →They become mutually exclusive — opening one closes the others in the group
  • →Nothing functional; it's purely a CSS styling hook
  • →They open and close together, in sync

toggle And beforetoggle Events Carry Old/New State. The toggle event fires after a <details> element's open state changes, and the newer, cancelable beforetoggle event fires just before — both carry newState and oldState properties ("open"/"closed"), letting you react to or intercept state changes, such as lazy-loading content only when a panel is first opened.

The toggle Event. What does the toggle event's newState property tell you?

  • →Whether the details element is now "open" or "closed"
  • →A boolean for whether the element is currently visible in the viewport
  • →The current progress of an open/close CSS animation

Styling ::marker And Animating Open/Close Height. The default disclosure triangle is the <summary> element's ::marker pseudo-element, fully restylable or removable (list-style: none, or ::marker { content: '' }); animating the actual open/close HEIGHT transition (rather than just opacity) has historically been the hard part, now addressed by the interpolate-size CSS property enabling auto-to-fixed height transitions.

Animating <details> Open/Close. What CSS pseudo-element controls the default disclosure triangle on <summary>?

  • →::marker
  • →::before, requiring content: "" to be set manually first
  • →There's no styling hook; it's a fixed browser image

Accessibility: Built-In Disclosure Semantics, With One Real Pitfall. <summary> automatically behaves like a button (keyboard-activatable with Enter/Space, focusable, and announced with an implicit expanded/collapsed state) with zero ARIA needed — but placing another genuinely interactive element (a link, a button) inside <summary> creates nested-interactive-control markup, which is invalid and produces unpredictable, inconsistent behavior across browsers and assistive technology.

The Nested-Control Pitfall. Why is placing a <button> or <a> directly inside a <summary> element problematic?

  • →It creates nested interactive controls, which is invalid markup with unpredictable cross-browser/AT behavior
  • →It's purely a visual/CSS styling inconvenience with no functional impact
  • →It isn't actually a problem at all

Programmatic Control And When To Reach For A Custom Accordion Instead. The .open boolean property lets JS read or set state directly (details.open = true), useful for 'expand all' controls across a group without a shared name; but for accordions needing animated height beyond what interpolate-size covers cleanly in every target browser, or requiring more complex multi-panel state than exclusive/independent, a custom-built component may still be the more predictable choice.

Programmatic Control. How do you programmatically open every <details> element in a group at once from JavaScript, overriding the exclusive name behavior?

  • →Set the .open property to true directly on each element
  • →It's impossible to override the exclusive name grouping from JS
  • →The name attribute must be permanently removed first

Advanced <details>/<summary> Mastered. You now know how to build exclusive accordion groups with the name attribute, react to state changes via the toggle/beforetoggle events, restyle and animate the disclosure widget, and avoid the one genuine accessibility pitfall — nesting interactive controls inside <summary>.

Open A Disclosure Widget By Default. Add the open attribute so the <details> starts expanded instead of collapsed.

Level Up šŸš€

Advanced cheat sheets, SEO tricks, and interview prep for this topic.

Browser Support

ChromeSupported

Fully supported.

FirefoxSupported

Fully supported.

SafariSupported

Fully supported.

EdgeSupported

Fully supported.

Accessibility (A11y)

1<summary> Announces Expanded/Collapsed State Automatically — No ARIA Required

The implicit disclosure semantics mean screen reader users get correct state announcements without any manual aria-expanded management, as long as native <details>/<summary> is used rather than a custom-built div-based imitation.

2Never Nest A <button> Or <a> Directly Inside <summary>

This creates invalid nested interactive controls with unpredictable cross-browser and cross-AT behavior — place any additional action as a sibling within the <details> body instead.

SEO Implications

  • 1

    Content Inside A Collapsed <details> Is Present In The DOM And Indexable

    Search engines can access and index content inside a closed <details> element since it's genuinely part of the rendered DOM, not injected only on interaction — useful for FAQ-style content that benefits from being indexed while staying visually collapsed by default.

Best Practices

Use A Shared name Attribute For Any Accordion Where Only One Panel Should Be Open At A Time

This replaces manual JS state coordination entirely, and is less error-prone than a hand-rolled 'close all others' click handler.

Reach For interpolate-size Or A Measured-Height Transition Before Reaching For A JS Animation Library

Native CSS height animation covers the overwhelming majority of accordion animation needs without adding a dependency.

Frequent Bugs

THE BUG

Multiple accordion panels can be open simultaneously despite the design intending only one at a time.

THE FIX

Give all <details> elements in that group the same name attribute value, letting the browser enforce exclusivity natively.

THE BUG

A button inside <summary> doesn't reliably respond to clicks/keyboard activation across browsers.

THE FIX

Move the button out as a sibling inside the <details> body rather than nesting it inside <summary>, which is already an interactive control.

Real-World Examples

A FAQ Accordion With Lazy-Loaded Content

An exclusive FAQ accordion that only fetches a panel's detailed content the first time it's actually opened.

<details name="faq" data-id="shipping">
  <summary>Shipping options?</summary>
  <div class="panel"></div>
</details>
<script>
document.querySelectorAll("details[name=faq]").forEach(d => {
  d.addEventListener("toggle", async (e) => {
    if (e.newState === "open" && !d.dataset.loaded) {
      d.querySelector(".panel").textContent = await fetchFaqContent(d.dataset.id);
      d.dataset.loaded = "true";
    }
  });
});
</script>

Interview Prep

?Frequently Asked Questions

Pascual Vila

Pascual Vila

Frontend Instructor // Code Syllabus

Common Pitfalls & Errors

The Error //

Building a JS-managed accordion with a manual 'close all others' click handler instead of the native name attribute

<details name="faq">…</details> <details name="faq">…</details>

The Solution //

Give the grouped <details> elements the same name value and let the browser enforce exclusivity natively.

The Error //

Nesting a <button> or <a> directly inside <summary>

<summary>Order #4471</summary> <a href="/orders/4471">View full order</a>

The Solution //

Place the additional interactive control as a sibling within the <details> body instead, since <summary> is already an interactive disclosure control.

Lesson Glossary

[01]name (details)

Groups multiple <details> elements into a mutually exclusive accordion set.

Code Preview
<details name="faq">

[02]toggle event

Fires after a <details> element's open state changes.

Code Preview
e.newState === "open"

[03]::marker

The pseudo-element controlling <summary>'s default disclosure triangle.

Code Preview
summary::marker { content: "ā–ø"; }

[04]interpolate-size

A CSS property enabling transitions between auto and fixed sizes.

Code Preview
interpolate-size: allow-keywords;

Continue Learning