36 CSS Stacked Cards21 / 36

Pure CSSMIT licensed

Accordion Card

A single standalone card holding several nested layers of content. Click a layer's header and it expands while its neighbours smoothly compress within the card's fixed boundary — an all-in-one accordion that never grows the surrounding layout.

Published Updated

Live Demo
Try it

The code

<section class="scd-21" aria-label="Single accordion card">
  <div class="scd-21__card">
    <div class="scd-21__sec">
      <input type="radio" name="scd-21" id="scd-21-1" class="scd-21__r" checked>
      <label class="scd-21__h" for="scd-21-1" style="--c:oklch(0.66 0.16 20)">Overview</label>
      <div class="scd-21__b"><p>A pocket knife of a component — three panels, one fixed card, zero layout shift.</p></div>
    </div>
    <div class="scd-21__sec">
      <input type="radio" name="scd-21" id="scd-21-2" class="scd-21__r">
      <label class="scd-21__h" for="scd-21-2" style="--c:oklch(0.68 0.15 150)">Features</label>
      <div class="scd-21__b"><p>Keyboard-navigable, reduced-motion aware, and copy-paste ready with scoped styles.</p></div>
    </div>
    <div class="scd-21__sec">
      <input type="radio" name="scd-21" id="scd-21-3" class="scd-21__r">
      <label class="scd-21__h" for="scd-21-3" style="--c:oklch(0.66 0.16 265)">Usage</label>
      <div class="scd-21__b"><p>Drop the markup in, keep the <code>.scd-21</code> scope, and swap the copy. Done.</p></div>
    </div>
  </div>
</section>
.scd-21,
.scd-21 *,
.scd-21 *::before,
.scd-21 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.scd-21 {
  font-family: 'Segoe UI',system-ui,sans-serif;
  width: 100%;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 60px 20px;
  background: #101219;
}

.scd-21__card {
  width: min(360px,100%);
  height: 320px;
  display: flex;
  flex-direction: column;
  background: #1b1e28;
  border: 1px solid #2a2e3a;
  border-radius: 20px;
  overflow: hidden;
  box-shadow: 0 26px 54px -30px rgba(0,0,0,.8);
}

.scd-21__sec {
  display: flex;
  flex-direction: column;
  flex: 0 0 auto;
  min-height: 0;
  transition: flex-grow .45s cubic-bezier(.3,.9,.3,1);
}

.scd-21__sec:has(.scd-21__r:checked) {
  flex: 1 1 auto;
}

.scd-21__r {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
}

.scd-21__h {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 18px 22px;
  font-weight: 800;
  font-size: 16px;
  color: #c9cde0;
  cursor: pointer;
  border-top: 1px solid #262a36;
}

.scd-21__sec:first-child .scd-21__h {
  border-top: none;
}

.scd-21__h::before {
  content: "";
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: #3a4050;
  transition: background .3s;
}

.scd-21__r:checked ~ .scd-21__h {
  color: #fff;
}

.scd-21__r:checked ~ .scd-21__h::before {
  background: var(--c);
}

.scd-21__b {
  overflow: hidden;
  opacity: 0;
  max-height: 0;
  transition: opacity .4s,max-height .45s;
}

.scd-21__r:checked ~ .scd-21__b {
  opacity: 1;
  max-height: 200px;
}

.scd-21__b p {
  padding: 0 22px 22px;
  color: #aab0c2;
  font-size: 14px;
  line-height: 1.6;
}

.scd-21__b code {
  background: #0f1117;
  padding: 2px 5px;
  border-radius: 5px;
  font-size: 12px;
}

.scd-21__r:focus-visible ~ .scd-21__h {
  outline: 3px solid var(--c);
  outline-offset: -3px;
}

@media (prefers-reduced-motion: reduce) {
  .scd-21__sec,
    .scd-21__b {
    transition: none;
  }
}
/* No JavaScript — inside one fixed-size card, the checked section's flex-grow fills while siblings shrink to their headers, so the card box never changes height. */
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 Stacked Card 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: Accordion Card
Source: https://codefronts.com/components/css-stacked-cards/accordion-card/

A single standalone card holding several nested layers of content. Click a layer's header and it expands while its neighbours smoothly compress within the card's fixed boundary — an all-in-one accordion that never grows the surrounding layout.
## HTML
```html
<section class="scd-21" aria-label="Single accordion card">
  <div class="scd-21__card">
    <div class="scd-21__sec">
      <input type="radio" name="scd-21" id="scd-21-1" class="scd-21__r" checked>
      <label class="scd-21__h" for="scd-21-1" style="--c:oklch(0.66 0.16 20)">Overview</label>
      <div class="scd-21__b"><p>A pocket knife of a component — three panels, one fixed card, zero layout shift.</p></div>
    </div>
    <div class="scd-21__sec">
      <input type="radio" name="scd-21" id="scd-21-2" class="scd-21__r">
      <label class="scd-21__h" for="scd-21-2" style="--c:oklch(0.68 0.15 150)">Features</label>
      <div class="scd-21__b"><p>Keyboard-navigable, reduced-motion aware, and copy-paste ready with scoped styles.</p></div>
    </div>
    <div class="scd-21__sec">
      <input type="radio" name="scd-21" id="scd-21-3" class="scd-21__r">
      <label class="scd-21__h" for="scd-21-3" style="--c:oklch(0.66 0.16 265)">Usage</label>
      <div class="scd-21__b"><p>Drop the markup in, keep the <code>.scd-21</code> scope, and swap the copy. Done.</p></div>
    </div>
  </div>
</section>
```
## CSS
```css
.scd-21,
.scd-21 *,
.scd-21 *::before,
.scd-21 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.scd-21 {
  font-family: 'Segoe UI',system-ui,sans-serif;
  width: 100%;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 60px 20px;
  background: #101219;
}

.scd-21__card {
  width: min(360px,100%);
  height: 320px;
  display: flex;
  flex-direction: column;
  background: #1b1e28;
  border: 1px solid #2a2e3a;
  border-radius: 20px;
  overflow: hidden;
  box-shadow: 0 26px 54px -30px rgba(0,0,0,.8);
}

.scd-21__sec {
  display: flex;
  flex-direction: column;
  flex: 0 0 auto;
  min-height: 0;
  transition: flex-grow .45s cubic-bezier(.3,.9,.3,1);
}

.scd-21__sec:has(.scd-21__r:checked) {
  flex: 1 1 auto;
}

.scd-21__r {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
}

.scd-21__h {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 18px 22px;
  font-weight: 800;
  font-size: 16px;
  color: #c9cde0;
  cursor: pointer;
  border-top: 1px solid #262a36;
}

.scd-21__sec:first-child .scd-21__h {
  border-top: none;
}

.scd-21__h::before {
  content: "";
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: #3a4050;
  transition: background .3s;
}

.scd-21__r:checked ~ .scd-21__h {
  color: #fff;
}

.scd-21__r:checked ~ .scd-21__h::before {
  background: var(--c);
}

.scd-21__b {
  overflow: hidden;
  opacity: 0;
  max-height: 0;
  transition: opacity .4s,max-height .45s;
}

.scd-21__r:checked ~ .scd-21__b {
  opacity: 1;
  max-height: 200px;
}

.scd-21__b p {
  padding: 0 22px 22px;
  color: #aab0c2;
  font-size: 14px;
  line-height: 1.6;
}

.scd-21__b code {
  background: #0f1117;
  padding: 2px 5px;
  border-radius: 5px;
  font-size: 12px;
}

.scd-21__r:focus-visible ~ .scd-21__h {
  outline: 3px solid var(--c);
  outline-offset: -3px;
}

@media (prefers-reduced-motion: reduce) {
  .scd-21__sec,
    .scd-21__b {
    transition: none;
  }
}
```

## JavaScript
```js
/* No JavaScript — inside one fixed-size card, the checked section's flex-grow fills while siblings shrink to their headers, so the card box never changes height. */
```

How this works

Inside one card, each section is a radio + header + body. The bodies share a fixed-height flex column; checking a section expands its flex to fill the card while the others shrink to just their headers — so the total card height stays constant and nothing outside reflows. Transitions on flex-grow make the swap glide.

Radios (shared name = one open at a time) keep native arrow navigation, headers show an active accent, and :focus-visible rings the current header. Reduced-motion drops the flex tween.

Make it yours

  • Switch to checkboxes to allow several open sections.
  • Change the collapsed header height.
  • Retime the expand via the flex transition.
  • Recolour the active accent per section.

Gotchas — read before shipping

  • Animate flex-grow, not height, so the card box stays fixed (no CLS).
  • Keep collapsed bodies clipped with overflow:hidden.
  • Radios must stay focusable for keyboard use.

Browser support

ChromeSafariFirefoxEdge
111+15.4+121+111+

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

Flexbox flex-grow transitions + radio :checked; supported in all modern browsers.

Techniques used in this demo

Search CodeFronts

Loading…