---
title: "CSS Accordion Animations: Expand & Collapse Effects"
description: "Four free pure-CSS accordion animations: smooth grid-based height expansion, chevron rotation, content fade-in, and morphing icons. No JS required."
url: https://frontendhelpers.com/css-accordion-animations
updated: 2026-10-12
---

# CSS accordion animations

Smooth expand and collapse, rotating chevrons and morphing plus-minus icons — all pure CSS, most built on the native details element.

## The code for all 4 accordions, explained

Every effect above, with the markup to use and the complete CSS. Each one is self-contained: paste the CSS once, add the class, done.

### Smooth Accordion

Height auto can't be transitioned — but grid-template-rows 0fr → 1fr can. That's the modern trick for smooth accordions with no fixed max-height guesswork. The checkbox stays keyboard-focusable (Space toggles it); for proper button semantics use native details or a button with aria-expanded, as in our [accordion animation recipe](https://frontendhelpers.com/css-accordion-animation).

Markup

```html
<div class="fh-accordion">
  <input type="checkbox" id="q1" />
  <label class="fh-acc-head" for="q1">Question?</label>
  <div class="fh-acc-body"><div>
    <p>Answer content…</p>
  </div></div>
</div>
```

CSS

```css
.fh-accordion {
  position: relative;
  border: 1px solid #3a4358;
  border-radius: 10px;
  overflow: hidden;
}
/* Hidden visually but still focusable: display: none would
   make the accordion impossible to open from the keyboard */
.fh-accordion input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.fh-accordion input:focus-visible + .fh-acc-head {
  outline: 2px solid #22d3ee;
  outline-offset: -2px;
}
.fh-acc-head {
  display: block;
  padding: 12px 16px;
  font-weight: 600;
  cursor: pointer;
  background: rgba(255, 255, 255, 0.04);
}
.fh-acc-body {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.35s cubic-bezier(0.22, 1, 0.36, 1);
}
.fh-acc-body > div { overflow: hidden; }
.fh-acc-body p { padding: 12px 16px; margin: 0; opacity: 0.75; }
.fh-accordion input:checked ~ .fh-acc-body {
  grid-template-rows: 1fr;
}
```

### Chevron Rotate

Native

gives you the open/close behaviour and accessibility for free — the \[open\] attribute selector drives the rotation.

Markup

```html
<details class="fh-details">
  <summary>Question? <span class="fh-acc-chevron">▾</span></summary>
  <p>Answer…</p>
</details>
```

CSS

```css
.fh-details {
  border: 1px solid #3a4358;
  border-radius: 10px;
  padding: 0 16px;
}
.fh-details summary {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  padding: 12px 0;
  cursor: pointer;
  font-weight: 600;
  list-style: none;
}
.fh-details summary::-webkit-details-marker { display: none; }
.fh-details p { padding: 0 0 12px; margin: 0; opacity: 0.75; }
.fh-acc-chevron {
  display: inline-block;
  transition: transform 0.3s cubic-bezier(0.22, 1, 0.36, 1);
}
.fh-details[open] .fh-acc-chevron { transform: rotate(180deg); }
```

### Content Fade-In

Layer this on any accordion: the panel content animates in each time it opens, making the reveal feel deliberate instead of abrupt.

Markup

```html
<details class="fh-details fh-acc-reveal">
  <summary>Question?</summary>
  <p>Answer…</p>
</details>
```

CSS

```css
.fh-details {
  border: 1px solid #3a4358;
  border-radius: 10px;
  padding: 0 16px;
}
.fh-details summary {
  padding: 12px 0;
  cursor: pointer;
  font-weight: 600;
  list-style: none;
}
.fh-details summary::-webkit-details-marker { display: none; }
.fh-details p { padding: 0 0 12px; margin: 0; opacity: 0.75; }
.fh-acc-reveal[open] p {
  animation: fh-accFade 0.35s ease both;
}
@keyframes fh-accFade {
  from { opacity: 0; transform: translateY(-6px); }
  to { opacity: 0.75; transform: translateY(0); }
}
```

### Plus / Minus Morph

Two bars drawn with pseudo-elements; on open, the vertical bar rotates into the horizontal one and fades — a tiny morph that reads as premium.

Markup

```html
<details class="fh-details">
  <summary>Question? <span class="fh-plusminus"></span></summary>
  <p>Answer…</p>
</details>
```

CSS

```css
.fh-details {
  border: 1px solid #3a4358;
  border-radius: 10px;
  padding: 0 16px;
}
.fh-details summary {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  padding: 12px 0;
  cursor: pointer;
  font-weight: 600;
  list-style: none;
}
.fh-details summary::-webkit-details-marker { display: none; }
.fh-details p { padding: 0 0 12px; margin: 0; opacity: 0.75; }
.fh-plusminus {
  position: relative;
  width: 14px;
  height: 14px;
  flex-shrink: 0;
}
.fh-plusminus::before,
.fh-plusminus::after {
  content: '';
  position: absolute;
  inset: 0;
  margin: auto;
  background: #06b6d4;
  border-radius: 2px;
  transition: transform 0.3s ease, opacity 0.3s ease;
}
.fh-plusminus::before { width: 14px; height: 2px; }
.fh-plusminus::after { width: 2px; height: 14px; }
.fh-details[open] .fh-plusminus::after { transform: rotate(90deg); opacity: 0; }
.fh-details[open] .fh-plusminus::before { transform: rotate(180deg); }
```

## Solving the height: auto problem

The classic accordion frustration is that `height: auto` cannot be transitioned — CSS needs two numeric values to interpolate between, and "auto" isn't one. For years the workaround was guessing a `max-height` large enough to fit any content, which produces a delay on close (the transition runs through the unused space) and breaks whenever content exceeds the guess.

The modern solution is `grid-template-rows: 0fr` transitioning to `1fr`, with the content wrapped in a child that has `overflow: hidden`. Fractional units _are_ interpolatable, so the row grows smoothly to exactly the content's height — no magic numbers, no guessing, and no delay.

## Use the native details element where you can

Three of the four effects here build on `<details>` and `<summary>`, which give you the open/close behaviour, keyboard support and screen reader semantics for free. The `[open]` attribute selector then drives your animation — no state management, no ARIA to maintain.

The trade-off is that `<details>` toggles instantly, so animating the height itself requires either the grid technique on a wrapper or the newer `::details-content` support. Animating the icon and fading the content, as these effects do, works everywhere today.

## Accordions and FAQ content

Accordions are the standard pattern for FAQ sections — including on this site — and they're safe for SEO: content inside a collapsed `<details>` is in the HTML and Google indexes it normally. Pair it with `FAQPage` structured data and you're eligible for FAQ rich results.

Where accordions go wrong is hiding content people need. If most visitors will want most of the answers, hiding them behind clicks adds friction for no benefit. Reserve accordions for genuinely optional or reference-style content, and consider opening the first item by default so the pattern is obvious.

## Frequently asked questions

### How do I animate height auto in CSS?

Transition grid-template-rows from 0fr to 1fr on a grid container, with the content in a child that has overflow: hidden. Fractional units are interpolatable, so the row grows to exactly the content height without max-height guesswork.

### Do accordions hurt SEO?

No. Content inside a collapsed details element is present in the HTML and Google indexes it normally. Pairing an FAQ accordion with FAQPage structured data can even make you eligible for rich results.

### Should I use details and summary or build my own accordion?

Use details and summary wherever possible — they provide open and close behaviour, keyboard support and screen reader semantics for free. Build your own only when you need behaviour the native element cannot express, such as a single-open group.

## Related categories

- [Animate Accordion Height in CSS: interpolate-size & More](https://frontendhelpers.com/css-accordion-animation): Animate accordion height to auto: the grid-rows trick that works everywhere, interpolate-size, ::details-content and exclusive details groups.
 
- [Menus & Dropdowns](https://frontendhelpers.com/css-menu-animations): Dropdown fades, grows and staggered items
 
- [Forms & Inputs](https://frontendhelpers.com/css-form-animations): Focus glows, floating labels and toggles
 
- [UI Feedback](https://frontendhelpers.com/css-ui-feedback-animations): Tooltips, toasts, modals and tab underlines
