Creating Accessible, Stylish Accordions
The HTML <details>
and <summary>
elements provide a native, semantic way to create disclosure widgets—interactive controls that let users show or hide sections of content without any JavaScript. From simple “Read more” toggles to fully featured accordion interfaces, these elements ship built‑in accessibility: keyboard support, screen‑reader roles, and authorizable markup that degrades gracefully when scripts are disabled or in older browsers.
Unlike custom JavaScript accordions, <details>
offers:
- No scripting dependency: The browser handles open/close state, reducing maintenance overhead.
- Built‑in accessibility: Screen readers announce the collapsed or expanded state, and keyboard users can toggle via Enter or Space.
- Semantic clarity: Authors express intent directly in HTML, improving SEO and maintainability.
- Lightweight performance: Zero runtime cost, minimal CSS overrides, and full progressive enhancement.
Whether you’re building a knowledgebase accordion, a progressive enhancement toggle for advanced settings, or an interactive FAQ, this guide will equip you with the knowledge and examples you need to master <details>
and <summary>
for robust, accessible disclosure widgets.
1. What Are <details>
and <summary>
?
At its simplest, the <details>
element represents a collapsible container. Its first child must be a <summary>
element, which serves as the visible header or trigger. When the user clicks or activates the <summary>
, the browser toggles the open
attribute on <details>
, revealing or hiding the rest of its content.
<details>
<summary>More about our product</summary>
<p>Our product offers three core features: …</p>
</details>
Native Behavior
- Disclosure icon: Browsers typically render a triangle or caret marker beside the
<summary>
, pointing right when collapsed and down when expanded. - Toggling state: Clicking the
<summary>
or pressing Enter/Space when focused toggles theopen
attribute. - No JavaScript required: The user agent handles all state changes automatically, so authors need only semantic markup.
Why Choose <details>
?
- Contrast with JS accordions: Custom accordions often require elaborate event wiring, ARIA roles, and state management.
<details>
removes boilerplate. - Implicit ARIA semantics: Assistive technologies recognize
<summary>
as a button witharia-expanded
, without extra attributes. - Progressive enhancement: In browsers without native support, content remains visible by default—ensuring core information is never lost.
By leveraging <details>
and <summary>
, you gain a robust foundation for disclosure widgets that “just work,” while still allowing you to layer on advanced behaviors, styles, and interactivity as needed.
2. Basic Example & Syntax
A minimal accordion item requires only three lines of HTML:
<details>
<summary>Product Specifications</summary>
<p>Dimensions: 10×20×5 cm<br>
Weight: 1.2 kg<br>
Material: Aluminum alloy</p>
</details>
Key Requirements
<summary>
as first child
The<summary>
element must appear immediately inside<details>
. Content before the<summary>
will not behave as the toggle.- Implicit
open
attribute
To render an item expanded by default, include theopen
attribute:
<details open> <summary>Expanded by default</summary> <p>Visible content on load.</p> </details>
- Content visibility
- When
<details>
lacks theopen
attribute, only the<summary>
and marker are visible. - Adding
open
(via user interaction or HTML attribute) reveals the remaining children.
- When
Why First‑Child Matters
If you accidentally place an explanatory paragraph before <summary>
, that text will always be visible and not part of the collapsed content. Always structure as:
<details>
<summary>Your toggle text</summary>
<!-- Collapsible content here -->
</details>
This simple pattern yields a fully functional disclosure widget across all modern browsers—no scripts, no fuss.
3. Accessibility & Screen Reader Behavior
One of the strongest arguments for <details>
is its built‑in accessibility. Unlike custom toggle scripts, which require ARIA attributes and keyboard handling, <details>
and <summary>
expose the right semantics out of the box.
Role & State Exposure
<summary>
is announced as a button by most screen readers (e.g., NVDA, JAWS, VoiceOver).- The expanded/collapsed state corresponds to
aria-expanded="true"
or"false"
, relayed automatically without author intervention. - Keyboard support: Users can Tab into the
<summary>
and press Enter or Space to toggle. Focus outline is applied by default for clarity.
Screen Reader Quirks
Different screen readers handle nested headings and focus differently:
- NVDA (Windows): Reads
<summary>
text as a button and announces “collapsed” or “expanded.” - JAWS (Windows): Similar behavior, but sometimes requires double‑press of Enter–Space sequences; testing is essential.
- VoiceOver (macOS/iOS): Taps into the Button role, announcing state changes but may not read updated content automatically—users must navigate into the region.
Best Practices for Accessibility
- Preserve focus styles
Never remove the default outline on<summary>
, as keyboard users rely on it. - Avoid nested interactive elements
Don’t place links or buttons inside<summary>
without careful testing—some screen readers may skip nested focusable controls. - Provide context
If you have multiple disclosure widgets, include unique and descriptive<summary>
text (e.g., “Shipping details,” “Payment options”) to avoid confusion. - Test with real assistive tech
Emulators and code validators are helpful, but nothing replaces testing on actual devices and screen readers to catch quirks.
By relying on <details>
’ inherent semantics, you satisfy many WCAG requirements—such as focusability, keyboard operability, and clear state communication—right out of the HTML.
4. Styling <summary>
and Custom Icons
Browsers render <summary>
akin to a list item with a built-in marker, but you can override these defaults to match your design system.
Basic Styling
details > summary {
padding: 0.5em 1em;
background-color: #f7f7f7;
cursor: pointer;
border: 1px solid #ccc;
border-radius: 4px;
}
Custom Disclosure Markers
Using ::marker
details > summary::marker {
font-size: 1.2em;
content: "+"; /* Collapsed state */
}
details[open] > summary::marker {
content: "–"; /* Expanded state */
}
Using Pseudo‑Elements
For broader browser support and greater control, hide the native marker and insert your own:
details > summary {
position: relative;
list-style: none; /* Remove default marker */
padding-left: 1.5em; /* Space for custom icon */
}
details > summary::before {
content: "+";
position: absolute;
left: 0;
top: 0.1em;
font-size: 1.2em;
transition: transform 0.2s ease;
}
details[open] > summary::before {
content: "–";
transform: rotate(180deg);
}
Styling the Expanded Panel
details > *:not(summary) {
padding: 1em;
border: 1px solid #ccc;
border-top: none;
animation: fadeIn 0.2s ease;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(-5px); }
to { opacity: 1; transform: translateY(0); }
}
Important: If you remove or override the marker icon, ensure you replace it with an equally clear visual cue—otherwise sighted users won’t know the element is interactive.
5. Enhanced Markup & Semantic Headings
You can nest richer markup inside <summary>
, such as headings or inline formatting, but be mindful of semantic hierarchy and assistive‑tech behaviors.
Nesting Headings
<details>
<summary><h3>Section Title</h3></summary>
<p>Expanded content here…</p>
</details>
- Pros: Maintains heading semantics for SEO and screen‑reader navigation.
- Cons: Some screen readers may skip nested headings or read them twice. Always test.
Inline Emphasis
<details>
<summary>
<strong>Show Advanced Options</strong>
</summary>
<!-- advanced settings fields -->
</details>
- Use inline elements (
<strong>
,<em>
,<span>
) for emphasis. - Avoid block‑level children other than headings—stick to inline or phrasing content within
<summary>
.
Accessibility Tip
If you nest a heading inside <summary>
, retain the role of <summary>
as a button. Do not remove draggable="false"
or other default roles. Testing across NVDA, JAWS, and VoiceOver ensures your markup remains navigable.
6. Real‑World Use Cases
6.1 FAQ Accordions
<section aria-label="FAQ">
<details>
<summary>What is your return policy?</summary>
<p>You can return any item within 30 days of purchase…</p>
</details>
<details>
<summary>Do you ship internationally?</summary>
<p>Yes, we ship to over 50 countries worldwide…</p>
</details>
</section>
- Pattern: Wrap
<details>
pairs in a<section>
witharia-label
or heading for grouping. - UX: Optionally allow only one item open at a time via a small script, but maintain native accessibility.
6.2 Code & Content Toggles
Developers often want to hide large code blocks by default:
<details>
<summary>Show JavaScript Example</summary>
<pre><code>
// your code snippet here
</code></pre>
</details>
- Automatically collapses heavy content, improving first‑paint performance.
6.3 Forms & Advanced Settings
<form>
<label><input type="checkbox" name="enableAdvanced"> Enable advanced settings</label>
<details>
<summary>Advanced Settings</summary>
<!-- form fields for expert users -->
</details>
</form>
- Tie
<details>
visibility to a checkbox via JavaScript or CSS:
input[name="enableAdvanced"]:checked ~ details { display: block; } input[name="enableAdvanced"]:not(:checked) ~ details { display: none; }
6.4 Nested Disclosure
For multi‑level content, nest <details>
:
<details>
<summary>Chapter 1</summary>
<details>
<summary>Section 1.1</summary>
<p>Details of section 1.1…</p>
</details>
<details>
<summary>Section 1.2</summary>
<p>Details of section 1.2…</p>
</details>
</details>
- Caution: Deep nesting may confuse screen‑reader users; ensure clear headings and logical structure.
These real‑world patterns showcase how <details>
powers everything from marketing FAQs to developer docs and configurable UIs—always with minimal code and built‑in accessibility.
7. Browser Support & Fallbacks
Supported Browsers
- Chrome, Firefox, Edge, Safari (desktop & mobile): Full support since roughly 2020.
- Opera: Supported.
- Legacy IE & EdgeHTML: No native support; content remains expanded by default.
Fallback Strategies
- Graceful degradation
In unsupported browsers,<details>
displays all children, ensuring no hidden critical content. - Polyfill
For consistent UI, include a small JavaScript polyfill such as details-element-polyfill:
<script src="details-polyfill.min.js" defer></script>
- CSS-only fallback
Hide all content by default and rely on a sibling checkbox hack:
.no-details details > *:not(summary) { display: block; } .no-details details:not([open]) > *:not(summary) { display: none; }
<html class="no-details"> ... </html>
Feature Detection
Use JavaScript to detect support and apply fallbacks:
if (!('open' in document.createElement('details'))) {
document.documentElement.classList.add('no-details');
}
By planning for unsupported environments, you ensure your UI remains functional and consistent.
8. Common Pitfalls & Accessibility Quirks
8.1 Nested Headings Issues
Some screen readers drop nested heading roles inside <summary>
. If SEO or accessible headings are crucial, consider placing the <h3>
outside and use <details>
only for content.
8.2 Removing Focus Outlines
Developers often remove focus styles for aesthetics. Don’t do this—ensure :focus
remains visible on <summary>
for keyboard users.
8.3 Inconsistent Announcements
- VoiceOver may not automatically read newly revealed content. Encourage users to navigate into the panel or provide an
aria-live
region.
8.4 Dragging & Selection
In certain browsers, users can inadvertently drag text inside <summary>
. Prevent this with CSS:
summary {
user-select: none;
-webkit-user-drag: none;
}
8.5 Event Bubbling
When intercepting clicks on <summary>
, note that events bubble. Avoid interfering with the default toggle unless absolutely necessary.
By understanding these quirks, you can avoid accessibility regressions and ensure consistent behavior across assistive technologies.
9. Performance & Searchability
Performance Benefits
- No JavaScript required: Removes external script payload.
- Fast initial render: Browsers parse markup and apply native disclosure without layout thrashing.
SEO & Indexing
- Collapsed content remains in the DOM and is generally indexed by search engines.
- Structured headings inside or alongside
<summary>
contribute to page outline and crawlability.
Unlike hidden content via display: none
, <details>
ensures that your content is available to bots and assistive tech, improving discoverability without sacrificing UX.
10. Modular Code & Component Patterns
For maintainable codebases, encapsulate <details>
logic and styles into reusable components:
export function initDisclosure(selector) {
document.querySelectorAll(selector).forEach(details => {
const summary = details.querySelector('summary');
summary.addEventListener('keydown', e => {
if (e.key === 'Enter' || e.key === ' ') details.open = !details.open;
});
});
}
/* _disclosure.scss */
.details {
& > summary { /* base styles */ }
&[open] > summary { /* open state */ }
}
- HTML attribute vs config: You can initialize all disclosures at once or target specific selectors via data attributes (e.g.,
data-disclosure
). - Separation of concerns: Keep behavior, presentation, and markup logically distinct for easier updates and theming.
11. FAQs
Q1: Can <summary>
contain heading tags?
Yes—nesting <h3>
or <span>
inside <summary>
is valid. However, test across screen readers, as some may skip nested headings.
Q2: How do I style the disclosure icon?
Hide the native marker with list-style: none
and insert custom icons via ::before
or ::marker
pseudoelements, toggling content based on the [open]
attribute.
Q3: Does <summary>
require JavaScript to function?
No. Native browser support handles toggling. JavaScript is only needed for polyfills or advanced behaviors (e.g., forced single-open accordions).
Q4: Is hidden content indexed by search engines?
Yes—collapsed <details>
content remains in the DOM, making it crawlable. This contrasts with content hidden via display: none
, which some crawlers may ignore.
12. Conclusion
The <details>
and <summary>
elements offer a lightweight, accessible, and performant way to implement disclosure widgets—ranging from simple accordions to complex interactive patterns—without the bloat of JavaScript frameworks. By embracing semantic HTML, you automatically satisfy keyboard and screen‑reader requirements, improve SEO, and provide a robust fallback for non‑supporting browsers. With the CSS techniques and modular patterns outlined above, you can customize markers, animate transitions, and layer advanced interactions—all while keeping your code maintainable. As you build your next FAQ section, settings panel, or content toggle, give <details>
a try. Your users—and your future self—will thank you for the simplicity and inclusivity it brings to the web.