Pure CSSMIT licensed

Horizontal FAQ Accordion Layout

The showpiece: five photo panels standing shoulder to shoulder, the active one unfolding sideways to reveal its Q&A while the others compress into elegant spines with vertically-written titles. Demo 10's fr-unit trick rotated 90° — grid-template-columns animating between 0fr and 1fr shares — plus writing-mode for the spine labels and radio-hack state so it is still pure CSS. The pattern behind a hundred award-site "expanding image accordion" hero sections, with the FAQ content making it useful.

Live Demo
Plain CSSTailwind v4
Try it

Complete Tailwind CSS landing page templates in HTML, React, Next.js and Vue · from $49

Cruip · Affiliate link

Browse Cruip templates

The code

<section class="cfa-15" aria-label="Horizontal FAQ accordion">
  <div class="cfa-15__stage">
    <div class="cfa-15__wrap">
      <header class="cfa-15__head">
        <h1>Plan your expedition</h1>
        <p>Five questions standing sideways — the open one unfolds. Arrow keys move between panels.</p>
      </header>
      <div class="cfa-15__strip">
        <div class="cfa-15__panel" style="--img:url('https://images.unsplash.com/photo-1464822759023-fed622ff2c3b?q=80&w=1200&auto=format&fit=crop')">
          <input type="radio" name="cfa15" id="cfa15-p1" class="cfa-15__rb" checked>
          <label class="cfa-15__spine" for="cfa15-p1"><h3>When to go?</h3></label>
          <div class="cfa-15__body"><div><h2>When is the best season?</h2><p>June through September for the high passes — long days, stable weather, open refuges. Shoulder months halve the crowds but add real weather risk above 2,500m.</p></div></div>
        </div>
        <div class="cfa-15__panel" style="--img:url('https://images.unsplash.com/photo-1551632811-561732d1e306?q=80&w=1200&auto=format&fit=crop')">
          <input type="radio" name="cfa15" id="cfa15-p2" class="cfa-15__rb">
          <label class="cfa-15__spine" for="cfa15-p2"><h3>Fitness level</h3></label>
          <div class="cfa-15__body"><div><h2>How fit do I need to be?</h2><p>Comfortable hiking 6–7 hours with a daypack, two days in a row. Our grade-2 routes need no technical skills; if you can do a hilly half-day hike smiling, twelve training weeks gets you there.</p></div></div>
        </div>
        <div class="cfa-15__panel" style="--img:url('https://images.unsplash.com/photo-1501554728187-ce583db33af7?q=80&w=1200&auto=format&fit=crop')">
          <input type="radio" name="cfa15" id="cfa15-p3" class="cfa-15__rb">
          <label class="cfa-15__spine" for="cfa15-p3"><h3>What's included</h3></label>
          <div class="cfa-15__body"><div><h2>What does the price include?</h2><p>Guides, refuge nights, breakfasts and dinners, luggage transfer between stages and safety kit. Flights, lunches and insurance are yours — full packing list on booking.</p></div></div>
        </div>
        <div class="cfa-15__panel" style="--img:url('https://images.unsplash.com/photo-1522163182402-834f871fd851?q=80&w=1200&auto=format&fit=crop')">
          <input type="radio" name="cfa15" id="cfa15-p4" class="cfa-15__rb">
          <label class="cfa-15__spine" for="cfa15-p4"><h3>Group size</h3></label>
          <div class="cfa-15__body"><div><h2>How big are the groups?</h2><p>Max 10, average 7, two certified guides per group. Solo travellers are half of every departure — the refuge table does the introductions by night two.</p></div></div>
        </div>
        <div class="cfa-15__panel" style="--img:url('https://images.unsplash.com/photo-1476514525535-07fb3b4ae5f1?q=80&w=1200&auto=format&fit=crop')">
          <input type="radio" name="cfa15" id="cfa15-p5" class="cfa-15__rb">
          <label class="cfa-15__spine" for="cfa15-p5"><h3>Cancellation</h3></label>
          <div class="cfa-15__body"><div><h2>What if I need to cancel?</h2><p>Free date changes until 30 days out, full refund minus deposit until 14, and the deposit converts to credit after that. Weather cancellations on our side refund everything.</p></div></div>
        </div>
      </div>
      <p class="cfa-15__foot">grid-template-columns 0fr→1fr + flex-grow transition — demo 10's trick, rotated. Folds vertical under 720px.</p>
    </div>
  </div>
</section>
.cfa-15,
.cfa-15 *,
.cfa-15 *::before,
.cfa-15 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.cfa-15 {
  --ink: oklch(0.98 0.004 250);
  --mut: oklch(0.88 0.01 250);
  --acc: oklch(0.8 0.15 80);
  width: 100%;
  min-height: 100vh;
  min-height: 100svh;
  display: block;
  font-family: 'Segoe UI',system-ui,sans-serif;
  color: var(--ink);
}

.cfa-15__stage {
  width: 100%;
  min-height: 100vh;
  min-height: 100svh;
  display: grid;
  place-items: center;
  padding: clamp(20px,4vw,56px);
  background: oklch(0.17 0.02 260);
  container: cfa15/inline-size;
}

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

.cfa-15__head h1 {
  font-size: clamp(26px,4cqi,40px);
  font-weight: 800;
  letter-spacing: -.025em;
}

.cfa-15__head p {
  margin-top: 8px;
  font-size: 14.5px;
  color: var(--mut);
}

.cfa-15__strip {
  margin-top: 26px;
  display: flex;
  gap: 10px;
  min-height: 420px;
}

.cfa-15__panel {
  position: relative;
  flex: 1;
  display: grid;
  grid-template-columns: 64px 0fr;
  border-radius: 18px;
  overflow: hidden;
  background-image: linear-gradient(oklch(0.2 0.03 260/.25),oklch(0.15 0.03 260/.7)),var(--img);
  background-size: cover;
  background-position: center;
  transition: grid-template-columns .6s cubic-bezier(.3,.8,.25,1),flex-grow .6s cubic-bezier(.3,.8,.25,1),outline-color .2s;
  outline: 2px solid transparent;
  outline-offset: 3px;
}

.cfa-15__panel:has(.cfa-15__rb:checked) {
  grid-template-columns: 64px 1fr;
  flex-grow: 3.2;
}

.cfa-15__panel:has(.cfa-15__rb:focus-visible) {
  outline-color: var(--acc);
}

.cfa-15__panel:not(:has(:checked)):hover {
  flex-grow: 1.15;
}

.cfa-15__rb {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.cfa-15__spine {
  display: grid;
  place-items: end center;
  padding: 18px 0;
  cursor: pointer;
  min-width: 44px;
}

.cfa-15__spine h3 {
  writing-mode: vertical-rl;
  rotate: 180deg;
  font-size: 14px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  text-shadow: 0 1px 12px oklch(0.15 0.03 260/.8);
  transition: color .3s;
}

.cfa-15__panel:has(:checked) .cfa-15__spine h3,
.cfa-15__spine:hover h3 {
  color: var(--acc);
}

.cfa-15__body {
  overflow: hidden;
  min-width: 0;
  display: grid;
  align-items: end;
}

.cfa-15__body>div {
  width: max(260px,26cqi);
  padding: 22px 24px 22px 8px;
  opacity: 0;
  translate: 14px 0;
  transition: opacity .4s .15s,translate .5s .15s cubic-bezier(.3,.8,.25,1);
}

.cfa-15__panel:has(:checked) .cfa-15__body>div {
  opacity: 1;
  translate: 0 0;
}

.cfa-15__body h2 {
  font-size: clamp(17px,2cqi,22px);
  font-weight: 800;
  letter-spacing: -.02em;
}

.cfa-15__body p {
  margin-top: 9px;
  font-size: 13.5px;
  line-height: 1.65;
  color: var(--mut);
}

.cfa-15__foot {
  margin-top: 20px;
  font-size: 12.5px;
  color: var(--mut);
}

@container cfa15 (width < 720px) {
  .cfa-15__strip {
    flex-direction: column;
    min-height: 0;
  }

  .cfa-15__panel {
    grid-template-columns: 1fr;
    grid-template-rows: 56px 0fr;
    transition: grid-template-rows .5s cubic-bezier(.3,.8,.25,1);
  }

  .cfa-15__panel:has(.cfa-15__rb:checked) {
    grid-template-columns: 1fr;
    grid-template-rows: 56px 1fr;
    flex-grow: 1;
  }

  .cfa-15__spine {
    place-items: center start;
    padding: 0 18px;
    min-height: 44px;
  }

  .cfa-15__spine h3 {
    writing-mode: horizontal-tb;
    rotate: none;
  }

  .cfa-15__body {
    min-height: 0;
  }

  .cfa-15__body>div {
    width: 100%;
    padding: 0 18px 20px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .cfa-15 * {
    transition-duration: .01ms !important;
    transition-delay: 0ms !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: Horizontal FAQ Accordion Layout
Source: https://codefronts.com/snippets/css-faq-accordion/horizontal-faq-accordion-layout/

The showpiece: five photo panels standing shoulder to shoulder, the active one unfolding sideways to reveal its Q&A while the others compress into elegant spines with vertically-written titles. Demo 10's fr-unit trick rotated 90° — grid-template-columns animating between 0fr and 1fr shares — plus writing-mode for the spine labels and radio-hack state so it is still pure CSS. The pattern behind a hundred award-site "expanding image accordion" hero sections, with the FAQ content making it useful.
## HTML
```html
<section class="cfa-15" aria-label="Horizontal FAQ accordion">
  <div class="cfa-15__stage">
    <div class="cfa-15__wrap">
      <header class="cfa-15__head">
        <h1>Plan your expedition</h1>
        <p>Five questions standing sideways — the open one unfolds. Arrow keys move between panels.</p>
      </header>
      <div class="cfa-15__strip">
        <div class="cfa-15__panel" style="--img:url('https://images.unsplash.com/photo-1464822759023-fed622ff2c3b?q=80&w=1200&auto=format&fit=crop')">
          <input type="radio" name="cfa15" id="cfa15-p1" class="cfa-15__rb" checked>
          <label class="cfa-15__spine" for="cfa15-p1"><h3>When to go?</h3></label>
          <div class="cfa-15__body"><div><h2>When is the best season?</h2><p>June through September for the high passes — long days, stable weather, open refuges. Shoulder months halve the crowds but add real weather risk above 2,500m.</p></div></div>
        </div>
        <div class="cfa-15__panel" style="--img:url('https://images.unsplash.com/photo-1551632811-561732d1e306?q=80&w=1200&auto=format&fit=crop')">
          <input type="radio" name="cfa15" id="cfa15-p2" class="cfa-15__rb">
          <label class="cfa-15__spine" for="cfa15-p2"><h3>Fitness level</h3></label>
          <div class="cfa-15__body"><div><h2>How fit do I need to be?</h2><p>Comfortable hiking 6–7 hours with a daypack, two days in a row. Our grade-2 routes need no technical skills; if you can do a hilly half-day hike smiling, twelve training weeks gets you there.</p></div></div>
        </div>
        <div class="cfa-15__panel" style="--img:url('https://images.unsplash.com/photo-1501554728187-ce583db33af7?q=80&w=1200&auto=format&fit=crop')">
          <input type="radio" name="cfa15" id="cfa15-p3" class="cfa-15__rb">
          <label class="cfa-15__spine" for="cfa15-p3"><h3>What's included</h3></label>
          <div class="cfa-15__body"><div><h2>What does the price include?</h2><p>Guides, refuge nights, breakfasts and dinners, luggage transfer between stages and safety kit. Flights, lunches and insurance are yours — full packing list on booking.</p></div></div>
        </div>
        <div class="cfa-15__panel" style="--img:url('https://images.unsplash.com/photo-1522163182402-834f871fd851?q=80&w=1200&auto=format&fit=crop')">
          <input type="radio" name="cfa15" id="cfa15-p4" class="cfa-15__rb">
          <label class="cfa-15__spine" for="cfa15-p4"><h3>Group size</h3></label>
          <div class="cfa-15__body"><div><h2>How big are the groups?</h2><p>Max 10, average 7, two certified guides per group. Solo travellers are half of every departure — the refuge table does the introductions by night two.</p></div></div>
        </div>
        <div class="cfa-15__panel" style="--img:url('https://images.unsplash.com/photo-1476514525535-07fb3b4ae5f1?q=80&w=1200&auto=format&fit=crop')">
          <input type="radio" name="cfa15" id="cfa15-p5" class="cfa-15__rb">
          <label class="cfa-15__spine" for="cfa15-p5"><h3>Cancellation</h3></label>
          <div class="cfa-15__body"><div><h2>What if I need to cancel?</h2><p>Free date changes until 30 days out, full refund minus deposit until 14, and the deposit converts to credit after that. Weather cancellations on our side refund everything.</p></div></div>
        </div>
      </div>
      <p class="cfa-15__foot">grid-template-columns 0fr→1fr + flex-grow transition — demo 10's trick, rotated. Folds vertical under 720px.</p>
    </div>
  </div>
</section>
```
## CSS
```css
.cfa-15,
.cfa-15 *,
.cfa-15 *::before,
.cfa-15 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.cfa-15 {
  --ink: oklch(0.98 0.004 250);
  --mut: oklch(0.88 0.01 250);
  --acc: oklch(0.8 0.15 80);
  width: 100%;
  min-height: 100vh;
  min-height: 100svh;
  display: block;
  font-family: 'Segoe UI',system-ui,sans-serif;
  color: var(--ink);
}

.cfa-15__stage {
  width: 100%;
  min-height: 100vh;
  min-height: 100svh;
  display: grid;
  place-items: center;
  padding: clamp(20px,4vw,56px);
  background: oklch(0.17 0.02 260);
  container: cfa15/inline-size;
}

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

.cfa-15__head h1 {
  font-size: clamp(26px,4cqi,40px);
  font-weight: 800;
  letter-spacing: -.025em;
}

.cfa-15__head p {
  margin-top: 8px;
  font-size: 14.5px;
  color: var(--mut);
}

.cfa-15__strip {
  margin-top: 26px;
  display: flex;
  gap: 10px;
  min-height: 420px;
}

.cfa-15__panel {
  position: relative;
  flex: 1;
  display: grid;
  grid-template-columns: 64px 0fr;
  border-radius: 18px;
  overflow: hidden;
  background-image: linear-gradient(oklch(0.2 0.03 260/.25),oklch(0.15 0.03 260/.7)),var(--img);
  background-size: cover;
  background-position: center;
  transition: grid-template-columns .6s cubic-bezier(.3,.8,.25,1),flex-grow .6s cubic-bezier(.3,.8,.25,1),outline-color .2s;
  outline: 2px solid transparent;
  outline-offset: 3px;
}

.cfa-15__panel:has(.cfa-15__rb:checked) {
  grid-template-columns: 64px 1fr;
  flex-grow: 3.2;
}

.cfa-15__panel:has(.cfa-15__rb:focus-visible) {
  outline-color: var(--acc);
}

.cfa-15__panel:not(:has(:checked)):hover {
  flex-grow: 1.15;
}

.cfa-15__rb {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.cfa-15__spine {
  display: grid;
  place-items: end center;
  padding: 18px 0;
  cursor: pointer;
  min-width: 44px;
}

.cfa-15__spine h3 {
  writing-mode: vertical-rl;
  rotate: 180deg;
  font-size: 14px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  text-shadow: 0 1px 12px oklch(0.15 0.03 260/.8);
  transition: color .3s;
}

.cfa-15__panel:has(:checked) .cfa-15__spine h3,
.cfa-15__spine:hover h3 {
  color: var(--acc);
}

.cfa-15__body {
  overflow: hidden;
  min-width: 0;
  display: grid;
  align-items: end;
}

.cfa-15__body>div {
  width: max(260px,26cqi);
  padding: 22px 24px 22px 8px;
  opacity: 0;
  translate: 14px 0;
  transition: opacity .4s .15s,translate .5s .15s cubic-bezier(.3,.8,.25,1);
}

.cfa-15__panel:has(:checked) .cfa-15__body>div {
  opacity: 1;
  translate: 0 0;
}

.cfa-15__body h2 {
  font-size: clamp(17px,2cqi,22px);
  font-weight: 800;
  letter-spacing: -.02em;
}

.cfa-15__body p {
  margin-top: 9px;
  font-size: 13.5px;
  line-height: 1.65;
  color: var(--mut);
}

.cfa-15__foot {
  margin-top: 20px;
  font-size: 12.5px;
  color: var(--mut);
}

@container cfa15 (width < 720px) {
  .cfa-15__strip {
    flex-direction: column;
    min-height: 0;
  }

  .cfa-15__panel {
    grid-template-columns: 1fr;
    grid-template-rows: 56px 0fr;
    transition: grid-template-rows .5s cubic-bezier(.3,.8,.25,1);
  }

  .cfa-15__panel:has(.cfa-15__rb:checked) {
    grid-template-columns: 1fr;
    grid-template-rows: 56px 1fr;
    flex-grow: 1;
  }

  .cfa-15__spine {
    place-items: center start;
    padding: 0 18px;
    min-height: 44px;
  }

  .cfa-15__spine h3 {
    writing-mode: horizontal-tb;
    rotate: none;
  }

  .cfa-15__body {
    min-height: 0;
  }

  .cfa-15__body>div {
    width: 100%;
    padding: 0 18px 20px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .cfa-15 * {
    transition-duration: .01ms !important;
    transition-delay: 0ms !important;
  }
}
```

How this works

Every panel is a grid with a fixed spine column and a fraction-unit content column; the checked one's fraction expands:

.strip{ display:flex; gap:10px }
.panel{ flex:1; display:grid;
        grid-template-columns:64px 0fr;   /* spine + collapsed */
        transition:grid-template-columns .6s cubic-bezier(.3,.8,.25,1),
                   flex-grow .6s cubic-bezier(.3,.8,.25,1) }
.panel:has(:checked){ grid-template-columns:64px 1fr; flex-grow:3.2 }
.panel > .body{ overflow:hidden; min-width:0 }

Two animations run together: the internal column going 0fr→1fr (same interpolation as demo 10, horizontal axis) and flex-grow 1→3.2 — flex-grow is a plain number, so it transitions too, letting the active panel claim more of the strip while siblings share the rest. The spine text stands upright via:

.spine h3{ writing-mode:vertical-rl; rotate:180deg }

(sideways-lr is the semantically nicer value but Safari only added it in 2024 — vertical-rl + rotate reads identically and works back years further.)

State is the radio hack because horizontal accordions are inherently exclusive — there is no room for two open panels. Note what this demo is honest about: horizontal disclosure is a display pattern for 3–6 visual items on wide screens, not an information pattern — which is why the container query at the bottom folds the whole strip back into a standard vertical accordion under 720px rather than pretending spines work on phones.

Make it yours

  • Panel count: 3–6 works; beyond that spines get sliver-thin. Adjust flex-grow (3.2) to taste — it is 'how greedy is the open panel'.
  • Images: each panel's --img custom property; the gradient overlay keeps spine text readable over any photo.
  • Hover preview: a :hover rule bumps closed panels' flex-grow to 1.15 — an invitation, not an opening.
  • Vertical fold: the under-720px container query is a complete second layout — customize it like a normal accordion; nothing horizontal leaks through.

Gotchas — read before shipping

  • min-width:0 on the expanding body is the horizontal twin of demo 10's min-height rule — without it the fr column refuses to close fully.
  • Animating width instead of grid-template-columns + flex-grow triggers text reflow every frame; the fr version lets the browser optimize, and the overflow-hidden body crops instead of rewrapping mid-animation.
  • writing-mode:vertical-rl without the 180° rotate reads top-to-bottom but 'backwards' for Latin labels lists — always pair them (or use sideways-lr where support allows).
  • Keyboard order: radios in one group arrow-key navigate horizontally for free — but ensure the label fills the whole spine so the click target isn't just the text.

Browser support

ChromeSafariFirefoxEdge
111+16+121+111+

Floor set by :has(), oklch(), @container as this demo is written. The core technique itself goes back further — Chrome 107+.

grid-template-columns interpolation matches demo 10's floors; flex-grow transitions are ancient. :has() for state needs Chrome 105 / Safari 15.4 / Firefox 121 — the biggest real floor here.

Techniques used in this demo

Search CodeFronts

Loading…