25 CSS FAQ Accordions02 / 25

Pure CSSMIT licensed

Native <details> FAQ Block with Custom Styled Icons

The most semantic FAQ possible: native <details>/<summary>, which browsers give you free keyboard support, screen-reader disclosure semantics, and even in-page find-and-expand for. This demo removes the default triangle marker, draws a custom animated chevron ring, and — the 2026 part — animates open/close to height:auto using ::details-content + interpolate-size: allow-keywords, with a graceful instant-open fallback wrapped in @supports. Styled as a warm editorial help page.

Published

Live Demo
Try it

The code

<section class="cfa-02" aria-label="Native details FAQ with custom icons">
  <div class="cfa-02__wrap">
    <header class="cfa-02__head">
      <h1>Help &amp; support</h1>
      <p>Built on native <code>&lt;details&gt;</code> — keyboard support, screen-reader semantics and find-in-page expansion are free. Try <kbd>Ctrl</kbd>+<kbd>F</kbd> for “passport”.</p>
    </header>
    <div class="cfa-02__list">
      <details class="cfa-02__item" open>
        <summary class="cfa-02__q">How long does delivery take?
          <span class="cfa-02__ic" aria-hidden="true"><svg viewBox="0 0 16 16" width="14" height="14"><path d="M3 6l5 5 5-5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
        </summary>
        <div class="cfa-02__a"><p>Standard delivery is 3–5 business days across the US, UK, Canada and Australia. Express (1–2 days) is available at checkout, and every order gets a tracked link the moment it leaves the warehouse.</p></div>
      </details>
      <details class="cfa-02__item">
        <summary class="cfa-02__q">Do I need a passport copy to book?
          <span class="cfa-02__ic" aria-hidden="true"><svg viewBox="0 0 16 16" width="14" height="14"><path d="M3 6l5 5 5-5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
        </summary>
        <div class="cfa-02__a"><p>Only for international itineraries. Upload a photo of the ID page once and we auto-fill every future booking — the file is encrypted at rest and deleted 30 days after your trip ends.</p></div>
      </details>
      <details class="cfa-02__item">
        <summary class="cfa-02__q">Can I change my order after placing it?
          <span class="cfa-02__ic" aria-hidden="true"><svg viewBox="0 0 16 16" width="14" height="14"><path d="M3 6l5 5 5-5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
        </summary>
        <div class="cfa-02__a"><p>Yes — orders can be edited for 60 minutes after checkout from your account page. After that the warehouse has it, but you can always refuse delivery or start a free return.</p></div>
      </details>
      <details class="cfa-02__item">
        <summary class="cfa-02__q">Which payment methods do you accept?
          <span class="cfa-02__ic" aria-hidden="true"><svg viewBox="0 0 16 16" width="14" height="14"><path d="M3 6l5 5 5-5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
        </summary>
        <div class="cfa-02__a"><p>All major cards, Apple Pay, Google Pay and PayPal. Business customers can request invoicing with NET-30 terms once approved.</p></div>
      </details>
    </div>
    <p class="cfa-02__foot">Open/close animates to <code>height:auto</code> via <code>::details-content</code> — no JavaScript, no wrappers. A demo from the CodeFronts FAQ collection.</p>
  </div>
</section>
.cfa-02,
.cfa-02 *,
.cfa-02 *::before,
.cfa-02 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.cfa-02 {
  --bg: oklch(0.97 0.012 85);
  --panel: oklch(0.995 0.004 90);
  --ink: oklch(0.25 0.02 60);
  --mut: oklch(0.5 0.025 60);
  --line: oklch(0.88 0.02 80);
  --acc: oklch(0.55 0.14 45);
  width: 100%;
  min-height: 100vh;
  min-height: 100svh;
  display: grid;
  place-items: center;
  padding: clamp(20px,4vw,56px);
  background: var(--bg);
  font-family: Georgia,'Times New Roman',serif;
  color: var(--ink);
}

.cfa-02__wrap {
  width: min(100%,640px);
}

.cfa-02__head h1 {
  font-size: clamp(30px,5cqi,42px);
  font-weight: 700;
  letter-spacing: -.02em;
}

.cfa-02__head p {
  margin-top: 10px;
  font-family: 'Segoe UI',system-ui,sans-serif;
  font-size: 14px;
  line-height: 1.65;
  color: var(--mut);
}

.cfa-02__head code,
.cfa-02__foot code {
  font-family: ui-monospace,Menlo,monospace;
  font-size: .85em;
  background: oklch(0.93 0.015 85);
  padding: 2px 6px;
  border-radius: 5px;
  color: var(--acc);
}

.cfa-02__head kbd {
  font-family: ui-monospace,Menlo,monospace;
  font-size: .82em;
  padding: 1px 6px;
  border: 1px solid var(--line);
  border-bottom-width: 2px;
  border-radius: 5px;
  background: var(--panel);
}

.cfa-02__list {
  margin-top: 26px;
  border-top: 1px solid var(--line);
  interpolate-size: allow-keywords;
}

.cfa-02__item {
  border-bottom: 1px solid var(--line);
}

.cfa-02__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: 44px;
  padding: 19px 4px;
  cursor: pointer;
  font-size: 18px;
  font-weight: 600;
  letter-spacing: -.01em;
  list-style: none;
  transition: color .2s;
}

.cfa-02__q::-webkit-details-marker {
  display: none;
}

.cfa-02__q:hover {
  color: var(--acc);
}

.cfa-02__q:focus-visible {
  outline: 2px solid var(--acc);
  outline-offset: 3px;
  border-radius: 6px;
}

.cfa-02__ic {
  display: grid;
  place-items: center;
  flex: none;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: 1.5px solid var(--line);
  color: var(--acc);
  transition: rotate .4s cubic-bezier(.4,0,.2,1),background .3s,border-color .3s;
}

.cfa-02__item[open] .cfa-02__ic {
  rotate: -180deg;
  background: color-mix(in oklch,var(--acc) 12%,transparent);
  border-color: color-mix(in oklch,var(--acc) 40%,var(--line));
}

.cfa-02__a p {
  padding: 2px 4px 20px;
  font-family: 'Segoe UI',system-ui,sans-serif;
  font-size: 14.5px;
  line-height: 1.75;
  color: var(--mut);
  max-width: 58ch;
}

@supports (interpolate-size: allow-keywords) {
  .cfa-02__item::details-content {
    height: 0;
    overflow: clip;
    opacity: 0;
    transition: height .4s cubic-bezier(.4,0,.2,1),opacity .35s,content-visibility .4s allow-discrete;
  }

  .cfa-02__item[open]::details-content {
    height: auto;
    opacity: 1;
  }
}

.cfa-02__foot {
  margin-top: 22px;
  font-family: 'Segoe UI',system-ui,sans-serif;
  font-size: 12.5px;
  color: var(--mut);
}

@media (prefers-reduced-motion: reduce) {
  .cfa-02 *,
    .cfa-02 .cfa-02__item::details-content {
    transition-duration: .01ms !important;
  }
}
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS FAQ Accordion from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Native <details> FAQ Block with Custom Styled Icons
Source: https://codefronts.com/snippets/css-faq-accordion/native-details-faq-block-with-custom-styled-icons/

The most semantic FAQ possible: native <details>/<summary>, which browsers give you free keyboard support, screen-reader disclosure semantics, and even in-page find-and-expand for. This demo removes the default triangle marker, draws a custom animated chevron ring, and — the 2026 part — animates open/close to height:auto using ::details-content + interpolate-size: allow-keywords, with a graceful instant-open fallback wrapped in @supports. Styled as a warm editorial help page.
## HTML
```html
<section class="cfa-02" aria-label="Native details FAQ with custom icons">
  <div class="cfa-02__wrap">
    <header class="cfa-02__head">
      <h1>Help &amp; support</h1>
      <p>Built on native <code>&lt;details&gt;</code> — keyboard support, screen-reader semantics and find-in-page expansion are free. Try <kbd>Ctrl</kbd>+<kbd>F</kbd> for “passport”.</p>
    </header>
    <div class="cfa-02__list">
      <details class="cfa-02__item" open>
        <summary class="cfa-02__q">How long does delivery take?
          <span class="cfa-02__ic" aria-hidden="true"><svg viewBox="0 0 16 16" width="14" height="14"><path d="M3 6l5 5 5-5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
        </summary>
        <div class="cfa-02__a"><p>Standard delivery is 3–5 business days across the US, UK, Canada and Australia. Express (1–2 days) is available at checkout, and every order gets a tracked link the moment it leaves the warehouse.</p></div>
      </details>
      <details class="cfa-02__item">
        <summary class="cfa-02__q">Do I need a passport copy to book?
          <span class="cfa-02__ic" aria-hidden="true"><svg viewBox="0 0 16 16" width="14" height="14"><path d="M3 6l5 5 5-5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
        </summary>
        <div class="cfa-02__a"><p>Only for international itineraries. Upload a photo of the ID page once and we auto-fill every future booking — the file is encrypted at rest and deleted 30 days after your trip ends.</p></div>
      </details>
      <details class="cfa-02__item">
        <summary class="cfa-02__q">Can I change my order after placing it?
          <span class="cfa-02__ic" aria-hidden="true"><svg viewBox="0 0 16 16" width="14" height="14"><path d="M3 6l5 5 5-5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
        </summary>
        <div class="cfa-02__a"><p>Yes — orders can be edited for 60 minutes after checkout from your account page. After that the warehouse has it, but you can always refuse delivery or start a free return.</p></div>
      </details>
      <details class="cfa-02__item">
        <summary class="cfa-02__q">Which payment methods do you accept?
          <span class="cfa-02__ic" aria-hidden="true"><svg viewBox="0 0 16 16" width="14" height="14"><path d="M3 6l5 5 5-5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
        </summary>
        <div class="cfa-02__a"><p>All major cards, Apple Pay, Google Pay and PayPal. Business customers can request invoicing with NET-30 terms once approved.</p></div>
      </details>
    </div>
    <p class="cfa-02__foot">Open/close animates to <code>height:auto</code> via <code>::details-content</code> — no JavaScript, no wrappers. A demo from the CodeFronts FAQ collection.</p>
  </div>
</section>
```
## CSS
```css
.cfa-02,
.cfa-02 *,
.cfa-02 *::before,
.cfa-02 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.cfa-02 {
  --bg: oklch(0.97 0.012 85);
  --panel: oklch(0.995 0.004 90);
  --ink: oklch(0.25 0.02 60);
  --mut: oklch(0.5 0.025 60);
  --line: oklch(0.88 0.02 80);
  --acc: oklch(0.55 0.14 45);
  width: 100%;
  min-height: 100vh;
  min-height: 100svh;
  display: grid;
  place-items: center;
  padding: clamp(20px,4vw,56px);
  background: var(--bg);
  font-family: Georgia,'Times New Roman',serif;
  color: var(--ink);
}

.cfa-02__wrap {
  width: min(100%,640px);
}

.cfa-02__head h1 {
  font-size: clamp(30px,5cqi,42px);
  font-weight: 700;
  letter-spacing: -.02em;
}

.cfa-02__head p {
  margin-top: 10px;
  font-family: 'Segoe UI',system-ui,sans-serif;
  font-size: 14px;
  line-height: 1.65;
  color: var(--mut);
}

.cfa-02__head code,
.cfa-02__foot code {
  font-family: ui-monospace,Menlo,monospace;
  font-size: .85em;
  background: oklch(0.93 0.015 85);
  padding: 2px 6px;
  border-radius: 5px;
  color: var(--acc);
}

.cfa-02__head kbd {
  font-family: ui-monospace,Menlo,monospace;
  font-size: .82em;
  padding: 1px 6px;
  border: 1px solid var(--line);
  border-bottom-width: 2px;
  border-radius: 5px;
  background: var(--panel);
}

.cfa-02__list {
  margin-top: 26px;
  border-top: 1px solid var(--line);
  interpolate-size: allow-keywords;
}

.cfa-02__item {
  border-bottom: 1px solid var(--line);
}

.cfa-02__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: 44px;
  padding: 19px 4px;
  cursor: pointer;
  font-size: 18px;
  font-weight: 600;
  letter-spacing: -.01em;
  list-style: none;
  transition: color .2s;
}

.cfa-02__q::-webkit-details-marker {
  display: none;
}

.cfa-02__q:hover {
  color: var(--acc);
}

.cfa-02__q:focus-visible {
  outline: 2px solid var(--acc);
  outline-offset: 3px;
  border-radius: 6px;
}

.cfa-02__ic {
  display: grid;
  place-items: center;
  flex: none;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: 1.5px solid var(--line);
  color: var(--acc);
  transition: rotate .4s cubic-bezier(.4,0,.2,1),background .3s,border-color .3s;
}

.cfa-02__item[open] .cfa-02__ic {
  rotate: -180deg;
  background: color-mix(in oklch,var(--acc) 12%,transparent);
  border-color: color-mix(in oklch,var(--acc) 40%,var(--line));
}

.cfa-02__a p {
  padding: 2px 4px 20px;
  font-family: 'Segoe UI',system-ui,sans-serif;
  font-size: 14.5px;
  line-height: 1.75;
  color: var(--mut);
  max-width: 58ch;
}

@supports (interpolate-size: allow-keywords) {
  .cfa-02__item::details-content {
    height: 0;
    overflow: clip;
    opacity: 0;
    transition: height .4s cubic-bezier(.4,0,.2,1),opacity .35s,content-visibility .4s allow-discrete;
  }

  .cfa-02__item[open]::details-content {
    height: auto;
    opacity: 1;
  }
}

.cfa-02__foot {
  margin-top: 22px;
  font-family: 'Segoe UI',system-ui,sans-serif;
  font-size: 12.5px;
  color: var(--mut);
}

@media (prefers-reduced-motion: reduce) {
  .cfa-02 *,
    .cfa-02 .cfa-02__item::details-content {
    transition-duration: .01ms !important;
  }
}
```

How this works

The element does the state management; you only style it. Killing the default marker takes both syntaxes (WebKit uses a pseudo-element, the standard uses list-style):

summary{ list-style:none }            /* standard */
summary::-webkit-details-marker{ display:none }  /* Safari */

Then the headline act — animating to the content's natural height with zero wrappers and zero JS. ::details-content is a pseudo-element wrapping everything after the summary, and interpolate-size: allow-keywords opts the page into transitioning between a length and a keyword like auto:

details{ interpolate-size: allow-keywords }
details::details-content{
  height:0; overflow:clip; opacity:0;
  transition:height .4s ease, opacity .4s ease,
             content-visibility .4s allow-discrete;
}
details[open]::details-content{ height:auto; opacity:1 }

The content-visibility transition with allow-discrete is what keeps the closing animation visible: without it the content is yanked from rendering the instant open is removed. In browsers that don't support the pseudo-element yet, the @supports wrapper simply never applies — panels snap open and closed, which is exactly how <details> has behaved for a decade. Progressive enhancement, not polyfills.

Free bonus semantics: Chrome's find-in-page (Ctrl+F) auto-expands a closed <details> containing a match — your FAQ answers are searchable even while collapsed.

Make it yours

  • Icon: the chevron is a single inline SVG in the summary — swap the path for a plus, arrow, or brand glyph; the [open] rule only rotates it.
  • Default-open item: add the open attribute — it round-trips with the UI state.
  • Exclusive mode: add name="faq" to every details element and the browser closes siblings for you (demo 03).
  • Softer motion: change the two .4s durations; the icon and panel share the timing so they stay in sync.

Gotchas — read before shipping

  • summary { display:flex } also removes the marker in some browsers as a side effect — do not rely on it; keep the explicit list-style:none + ::-webkit-details-marker pair.
  • Do not put a heading INSIDE summary and expect heading semantics everywhere — summary maps to a button-like role and some screen readers drop the heading level; put the h2/h3 around the details block if you need document outline.
  • overflow:clip (not hidden) on ::details-content avoids creating a scroll container that can trap programmatic scrolling.
  • interpolate-size is inherited — declare it once on the list container rather than per-details if you have many.

Browser support

ChromeSafariFirefoxEdge
131+18.4+ (partial)instant fallback131+

<details> itself is universal (2020+ everywhere, IE excepted). The height-to-auto animation via ::details-content/interpolate-size is Chrome 131 / Edge 131 / Safari 18.4; Firefox gets instant open/close via the @supports fallback — fully functional, just unanimated.

Techniques used in this demo

Search CodeFronts

Loading…