Clean Markup

Zero JavaScript Accordions with HTML5 Details and Summary

Zero JavaScript Accordions with HTML5 Details and Summary

Expandable FAQ sections and collapsible disclosure widgets are among the most frequently over-engineered components on the web. Developers often reach for JavaScript click handlers, manual aria-expanded toggling, and height animations when native HTML5 already provides the <details> and <summary> elements with built-in keyboard (Enter and Space) and screen-reader support.

Example

<details>
  <summary>What is Clean Markup?</summary>
  <p>Writing semantic, accessible, and standards-compliant HTML, CSS, and JavaScript.</p>
</details>

Input : Frequently Asked Questions list
Output : Keyboard-accessible expandable accordion using pure HTML5 and CSS.

Implementation

<section class="faq-section" aria-labelledby="faq-heading">
  <h2 id="faq-heading">Frequently Asked Questions</h2>

  <details class="faq-item" open>
    <summary class="faq-item__summary">
      Why use native &lt;details&gt; instead of a custom div?
    </summary>
    <div class="faq-item__content">
      <p>
        The browser automatically manages focus, keyboard activation, and
        announces the expanded or collapsed state to assistive technology.
      </p>
    </div>
  </details>

  <details class="faq-item">
    <summary class="faq-item__summary">
      Can we style the disclosure triangle in CSS?
    </summary>
    <div class="faq-item__content">
      <p>
        Yes—you can hide the default marker using
        <code>summary::-webkit-details-marker</code> and replace it with a
        custom CSS indicator that rotates when <code>details[open]</code> is active.
      </p>
    </div>
  </details>
</section>
.faq-item {
  border: 1px solid #dedede;
  border-radius: 6px;
  margin-bottom: 12px;
  background: #ffffff;
}

.faq-item__summary {
  padding: 16px 20px;
  font-weight: 700;
  color: #082840;
  cursor: pointer;
  list-style: none;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.faq-item__summary::-webkit-details-marker {
  display: none;
}

.faq-item__summary::after {
  content: "+";
  font-size: 20px;
  color: #04ae92;
  transition: transform 150ms ease;
}

.faq-item[open] .faq-item__summary::after {
  transform: rotate(45deg);
}

.faq-item__content {
  padding: 0 20px 18px 20px;
  color: #424242;
}

Main Point: Adding the open boolean attribute to <details open> renders that item expanded on initial page load while remaining interactive.

Credits

Photo by Jess Bailey

← Home