11 / 25
All 25 in 25 Tailwind CSS FAQ Accordion
- 01Tailwind Peer-Checked FAQ Accordion with No JavaScript
- 02Tailwind Native Details/Summary FAQ with Custom Styled Icons
- 03Tailwind Exclusive Accordion — Only One FAQ Open at a Time
- 04Tailwind Multi-Open FAQ Accordion with a Live CSS Counter
- 05Tailwind CSS FAQ Accordion Template (Free, Copy-Paste)
- 06Tailwind Dark Mode FAQ Accordion with light-dark() and No .dark Class
- 07Tailwind Glassmorphism FAQ Accordion with Frosted Backdrop Blur
- 08Tailwind Minimalist E-Commerce FAQ Accordion for Product Pages
- 09Tailwind Neumorphic Soft-UI FAQ Accordion Cards
- 10Tailwind Animate Height Auto FAQ with grid-rows 0fr to 1fr
- 11Tailwind FAQ Chevron Rotate 180 Degrees on Toggle
- 12Tailwind Animated Plus to Minus Icon Morph FAQ Accordion
- 13Tailwind Spring Bounce FAQ Accordion with linear() Easing
- 14Tailwind Two-Column FAQ Accordion Grid with Independent Columns
- 15Tailwind Horizontal FAQ Accordion with Sideways Expanding Panels
- 16Tailwind Categorised FAQ Help Centre with a Sticky Sidebar Menu
- 17Tailwind Card-Style FAQ Panels with a Layered Shadow Elevation System
- 18Tailwind FAQ Accordion with a Live Search Bar Filter
- 19Tailwind Expand All and Collapse All FAQ Accordion Buttons
- 20Tailwind FAQ with a Still Have Questions Contact CTA Card
- 21Tailwind Accessible ARIA FAQ Accordion with Keyboard Navigation
- 22Tailwind FAQ with FAQPage JSON-LD Schema for Rich Snippets and AI Search
- 23Bootstrap 5 Accordion Rebuilt in Tailwind (and the JavaScript You Delete)
- 24Tailwind FAQ Component in React, Vue, Svelte and Astro (One Port Recipe)
- 25Tailwind FAQ with Voice Search Using the Speech Recognition API
Tailwind FAQ Chevron Rotate 180 Degrees on Toggle
The definitive treatment of the web's most-copied micro-interaction, ported: three chevron builds in one FAQ — inline SVG, a two-border CSS chevron, and a Unicode glyph — each rotating on group-open: with matched timing, plus the UX rules for which way a closed chevron should point and why the rotation duration must equal the panel's.
Complete Tailwind CSS landing page templates in HTML, React, Next.js and Vue · from $49
Cruip · Affiliate link
The code
<section class="tfa-11 w-full min-h-svh grid place-items-center bg-tfa11-bg font-tfa11-sans text-tfa11-ink px-5 py-12">
<div class="w-[min(680px,100%)]">
<header>
<h1 class="text-[clamp(28px,5vw,40px)] font-extrabold leading-[1.08] tracking-[-0.025em]">The 180° chevron, three ways</h1>
<p class="mt-3 max-w-[56ch] text-[15px] leading-relaxed text-tfa11-mut">Same rotation, three icon builds — SVG, pure CSS borders, Unicode. Matched <code class="rounded bg-tfa11-tint px-1.5 py-0.5 font-tfa11-mono text-[0.87em] text-tfa11-acc">duration-400</code> keeps icon and panel in sync.</p>
</header>
<div data-panel class="mt-8 flex flex-col gap-2.5">
<details class="group rounded-2xl border border-tfa11-edge bg-white shadow-[0_2px_8px_oklch(0.4_0.05_250/0.05)] transition-[border-color,box-shadow] duration-300 open:border-tfa11-accedge open:shadow-[0_14px_34px_-20px_oklch(0.45_0.14_250/0.4)]" open>
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3 px-5 py-4 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa11-acc focus-visible:rounded-2xl focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa11-acc [&::-webkit-details-marker]:hidden">
<span class="shrink-0 rounded-md bg-tfa11-tint px-2 py-1 font-tfa11-mono text-[10px] font-bold tracking-[0.05em] text-tfa11-acc">A · SVG</span>Which icon build should production use?
<span aria-hidden="true" class="ml-auto grid shrink-0 place-items-center text-tfa11-mut transition-[rotate,color] duration-400 ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:text-tfa11-acc group-open:rotate-180 group-open:text-tfa11-acc motion-reduce:transition-colors"><svg viewBox="0 0 16 16" width="16" height="16"><path d="M3 6l5 5 5-5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
</summary>
<p class="max-w-[60ch] px-5 pb-4 text-[14px] leading-[1.7] text-tfa11-mut">This one. <code class="rounded bg-tfa11-tint px-1.5 py-0.5 font-tfa11-mono text-[0.87em] text-tfa11-acc">stroke: currentColor</code> inherits your text colour automatically, the rounded caps stay crisp at every DPI, and rotating the whole SVG element avoids every alignment quirk the other two builds carry.</p>
</details>
<details class="group rounded-2xl border border-tfa11-edge bg-white shadow-[0_2px_8px_oklch(0.4_0.05_250/0.05)] transition-[border-color,box-shadow] duration-300 open:border-tfa11-accedge open:shadow-[0_14px_34px_-20px_oklch(0.45_0.14_250/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3 px-5 py-4 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa11-acc focus-visible:rounded-2xl focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa11-acc [&::-webkit-details-marker]:hidden">
<span class="shrink-0 rounded-md bg-tfa11-tint px-2 py-1 font-tfa11-mono text-[10px] font-bold tracking-[0.05em] text-tfa11-acc">B · borders</span>How does the zero-asset chevron work?
<span aria-hidden="true" class="ml-auto size-2.5 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa11-mut transition-[rotate,translate,border-color] duration-400 ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:border-tfa11-acc group-open:translate-y-0.5 group-open:rotate-[225deg] group-open:border-tfa11-acc motion-reduce:transition-colors"></span>
</summary>
<p class="max-w-[60ch] px-5 pb-4 text-[14px] leading-[1.7] text-tfa11-mut">A 9px square with only its right and bottom borders, pre-rotated 45° — so “rotate 180°” actually means <code class="rounded bg-tfa11-tint px-1.5 py-0.5 font-tfa11-mono text-[0.87em] text-tfa11-acc">rotate-[225deg]</code>, and a 2px translate nudge re-centres its optical middle. Zero assets, two gotchas.</p>
</details>
<details class="group rounded-2xl border border-tfa11-edge bg-white shadow-[0_2px_8px_oklch(0.4_0.05_250/0.05)] transition-[border-color,box-shadow] duration-300 open:border-tfa11-accedge open:shadow-[0_14px_34px_-20px_oklch(0.45_0.14_250/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3 px-5 py-4 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa11-acc focus-visible:rounded-2xl focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa11-acc [&::-webkit-details-marker]:hidden">
<span class="shrink-0 rounded-md bg-tfa11-tint px-2 py-1 font-tfa11-mono text-[10px] font-bold tracking-[0.05em] text-tfa11-acc">C · Unicode</span>When is a text arrow good enough?
<span aria-hidden="true" class="ml-auto shrink-0 -translate-y-0.5 text-[18px] font-bold leading-none text-tfa11-mut transition-[rotate,translate,color] duration-400 ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:text-tfa11-acc group-open:translate-y-0.5 group-open:rotate-180 group-open:text-tfa11-acc motion-reduce:transition-colors">⌄</span>
</summary>
<p class="max-w-[60ch] px-5 pb-4 text-[14px] leading-[1.7] text-tfa11-mut">Prototypes and plain-text contexts. It costs one character, but its baseline position depends on the font stack — explicit sizing and <code class="rounded bg-tfa11-tint px-1.5 py-0.5 font-tfa11-mono text-[0.87em] text-tfa11-acc">leading-none</code> tame it, mostly. Ship SVG when it matters.</p>
</details>
<details class="group rounded-2xl border border-tfa11-edge bg-white shadow-[0_2px_8px_oklch(0.4_0.05_250/0.05)] transition-[border-color,box-shadow] duration-300 open:border-tfa11-accedge open:shadow-[0_14px_34px_-20px_oklch(0.45_0.14_250/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3 px-5 py-4 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa11-acc focus-visible:rounded-2xl focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa11-acc [&::-webkit-details-marker]:hidden">
<span class="shrink-0 rounded-md bg-tfa11-tint px-2 py-1 font-tfa11-mono text-[10px] font-bold tracking-[0.05em] text-tfa11-acc">UX</span>Which way should a closed chevron point?
<span aria-hidden="true" class="ml-auto grid shrink-0 place-items-center text-tfa11-mut transition-[rotate,color] duration-400 ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:text-tfa11-acc group-open:rotate-180 group-open:text-tfa11-acc motion-reduce:transition-colors"><svg viewBox="0 0 16 16" width="16" height="16"><path d="M3 6l5 5 5-5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
</summary>
<p class="max-w-[60ch] px-5 pb-4 text-[14px] leading-[1.7] text-tfa11-mut">Down when closed (content continues below), up when open. Right-pointing chevrons signal navigation into another screen — using one on an accordion misleads screen-magnifier and low-vision users especially. And match the rotation duration to the panel, or mismatched timings read as jank.</p>
</details>
</div>
<p class="mt-6 text-[12.5px] text-tfa11-mut">All three rotate under <code class="rounded bg-tfa11-tint px-1.5 py-0.5 font-tfa11-mono text-[0.87em] text-tfa11-acc">group-open:</code> — build B to 225°, because it starts at 45°.</p>
</div>
</section><section class="tfa-11 w-full min-h-svh grid place-items-center bg-tfa11-bg font-tfa11-sans text-tfa11-ink px-5 py-12">
<div class="w-[min(680px,100%)]">
<header>
<h1 class="text-[clamp(28px,5vw,40px)] font-extrabold leading-[1.08] tracking-[-0.025em]">The 180° chevron, three ways</h1>
<p class="mt-3 max-w-[56ch] text-[15px] leading-relaxed text-tfa11-mut">Same rotation, three icon builds — SVG, pure CSS borders, Unicode. Matched <code class="rounded bg-tfa11-tint px-1.5 py-0.5 font-tfa11-mono text-[0.87em] text-tfa11-acc">duration-400</code> keeps icon and panel in sync.</p>
</header>
<div data-panel class="mt-8 flex flex-col gap-2.5">
<details class="group rounded-2xl border border-tfa11-edge bg-white shadow-[0_2px_8px_oklch(0.4_0.05_250/0.05)] transition-[border-color,box-shadow] duration-300 open:border-tfa11-accedge open:shadow-[0_14px_34px_-20px_oklch(0.45_0.14_250/0.4)]" open>
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3 px-5 py-4 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa11-acc focus-visible:rounded-2xl focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa11-acc [&::-webkit-details-marker]:hidden">
<span class="shrink-0 rounded-md bg-tfa11-tint px-2 py-1 font-tfa11-mono text-[10px] font-bold tracking-[0.05em] text-tfa11-acc">A · SVG</span>Which icon build should production use?
<span aria-hidden="true" class="ml-auto grid shrink-0 place-items-center text-tfa11-mut transition-[rotate,color] duration-400 ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:text-tfa11-acc group-open:rotate-180 group-open:text-tfa11-acc motion-reduce:transition-colors"><svg viewBox="0 0 16 16" width="16" height="16"><path d="M3 6l5 5 5-5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
</summary>
<p class="max-w-[60ch] px-5 pb-4 text-[14px] leading-[1.7] text-tfa11-mut">This one. <code class="rounded bg-tfa11-tint px-1.5 py-0.5 font-tfa11-mono text-[0.87em] text-tfa11-acc">stroke: currentColor</code> inherits your text colour automatically, the rounded caps stay crisp at every DPI, and rotating the whole SVG element avoids every alignment quirk the other two builds carry.</p>
</details>
<details class="group rounded-2xl border border-tfa11-edge bg-white shadow-[0_2px_8px_oklch(0.4_0.05_250/0.05)] transition-[border-color,box-shadow] duration-300 open:border-tfa11-accedge open:shadow-[0_14px_34px_-20px_oklch(0.45_0.14_250/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3 px-5 py-4 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa11-acc focus-visible:rounded-2xl focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa11-acc [&::-webkit-details-marker]:hidden">
<span class="shrink-0 rounded-md bg-tfa11-tint px-2 py-1 font-tfa11-mono text-[10px] font-bold tracking-[0.05em] text-tfa11-acc">B · borders</span>How does the zero-asset chevron work?
<span aria-hidden="true" class="ml-auto size-2.5 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa11-mut transition-[rotate,translate,border-color] duration-400 ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:border-tfa11-acc group-open:translate-y-0.5 group-open:rotate-[225deg] group-open:border-tfa11-acc motion-reduce:transition-colors"></span>
</summary>
<p class="max-w-[60ch] px-5 pb-4 text-[14px] leading-[1.7] text-tfa11-mut">A 9px square with only its right and bottom borders, pre-rotated 45° — so “rotate 180°” actually means <code class="rounded bg-tfa11-tint px-1.5 py-0.5 font-tfa11-mono text-[0.87em] text-tfa11-acc">rotate-[225deg]</code>, and a 2px translate nudge re-centres its optical middle. Zero assets, two gotchas.</p>
</details>
<details class="group rounded-2xl border border-tfa11-edge bg-white shadow-[0_2px_8px_oklch(0.4_0.05_250/0.05)] transition-[border-color,box-shadow] duration-300 open:border-tfa11-accedge open:shadow-[0_14px_34px_-20px_oklch(0.45_0.14_250/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3 px-5 py-4 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa11-acc focus-visible:rounded-2xl focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa11-acc [&::-webkit-details-marker]:hidden">
<span class="shrink-0 rounded-md bg-tfa11-tint px-2 py-1 font-tfa11-mono text-[10px] font-bold tracking-[0.05em] text-tfa11-acc">C · Unicode</span>When is a text arrow good enough?
<span aria-hidden="true" class="ml-auto shrink-0 -translate-y-0.5 text-[18px] font-bold leading-none text-tfa11-mut transition-[rotate,translate,color] duration-400 ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:text-tfa11-acc group-open:translate-y-0.5 group-open:rotate-180 group-open:text-tfa11-acc motion-reduce:transition-colors">⌄</span>
</summary>
<p class="max-w-[60ch] px-5 pb-4 text-[14px] leading-[1.7] text-tfa11-mut">Prototypes and plain-text contexts. It costs one character, but its baseline position depends on the font stack — explicit sizing and <code class="rounded bg-tfa11-tint px-1.5 py-0.5 font-tfa11-mono text-[0.87em] text-tfa11-acc">leading-none</code> tame it, mostly. Ship SVG when it matters.</p>
</details>
<details class="group rounded-2xl border border-tfa11-edge bg-white shadow-[0_2px_8px_oklch(0.4_0.05_250/0.05)] transition-[border-color,box-shadow] duration-300 open:border-tfa11-accedge open:shadow-[0_14px_34px_-20px_oklch(0.45_0.14_250/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3 px-5 py-4 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa11-acc focus-visible:rounded-2xl focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa11-acc [&::-webkit-details-marker]:hidden">
<span class="shrink-0 rounded-md bg-tfa11-tint px-2 py-1 font-tfa11-mono text-[10px] font-bold tracking-[0.05em] text-tfa11-acc">UX</span>Which way should a closed chevron point?
<span aria-hidden="true" class="ml-auto grid shrink-0 place-items-center text-tfa11-mut transition-[rotate,color] duration-400 ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:text-tfa11-acc group-open:rotate-180 group-open:text-tfa11-acc motion-reduce:transition-colors"><svg viewBox="0 0 16 16" width="16" height="16"><path d="M3 6l5 5 5-5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
</summary>
<p class="max-w-[60ch] px-5 pb-4 text-[14px] leading-[1.7] text-tfa11-mut">Down when closed (content continues below), up when open. Right-pointing chevrons signal navigation into another screen — using one on an accordion misleads screen-magnifier and low-vision users especially. And match the rotation duration to the panel, or mismatched timings read as jank.</p>
</details>
</div>
<p class="mt-6 text-[12.5px] text-tfa11-mut">All three rotate under <code class="rounded bg-tfa11-tint px-1.5 py-0.5 font-tfa11-mono text-[0.87em] text-tfa11-acc">group-open:</code> — build B to 225°, because it starts at 45°.</p>
</div>
</section>@import "tailwindcss";
@theme {
--color-tfa11-bg: #f6f7fb;
--color-tfa11-bg: oklch(0.97 0.008 250);
--color-tfa11-ink: #262b38;
--color-tfa11-ink: oklch(0.23 0.03 255);
--color-tfa11-mut: #5e6472;
--color-tfa11-mut: oklch(0.47 0.022 252);
--color-tfa11-edge: #e2e5ee;
--color-tfa11-edge: oklch(0.91 0.012 250);
--color-tfa11-accedge: #8fa6e4;
--color-tfa11-accedge: oklch(0.72 0.1 255);
--color-tfa11-tint: #e9eefb;
--color-tfa11-tint: oklch(0.94 0.028 255);
--color-tfa11-acc: #2f4ec4;
--color-tfa11-acc: oklch(0.47 0.19 260);
--font-tfa11-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--font-tfa11-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tfa-11 {
width: 100%;
min-height: 100svh;
}
.tfa-11 [data-panel] {
interpolate-size: allow-keywords;
}
@supports (interpolate-size: allow-keywords) {
.tfa-11 details::details-content {
height: 0;
overflow: clip;
opacity: 0;
transition: height .4s cubic-bezier(.4,0,.2,1), opacity .32s, content-visibility .4s allow-discrete;
}
.tfa-11 details[open]::details-content {
height: auto;
opacity: 1;
}
}
@media (prefers-reduced-motion: reduce) {
.tfa-11 details::details-content {
transition-duration: 1ms;
}
}@import "tailwindcss";
@theme {
--color-tfa11-bg: #f6f7fb;
--color-tfa11-bg: oklch(0.97 0.008 250);
--color-tfa11-ink: #262b38;
--color-tfa11-ink: oklch(0.23 0.03 255);
--color-tfa11-mut: #5e6472;
--color-tfa11-mut: oklch(0.47 0.022 252);
--color-tfa11-edge: #e2e5ee;
--color-tfa11-edge: oklch(0.91 0.012 250);
--color-tfa11-accedge: #8fa6e4;
--color-tfa11-accedge: oklch(0.72 0.1 255);
--color-tfa11-tint: #e9eefb;
--color-tfa11-tint: oklch(0.94 0.028 255);
--color-tfa11-acc: #2f4ec4;
--color-tfa11-acc: oklch(0.47 0.19 260);
--font-tfa11-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--font-tfa11-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tfa-11 {
width: 100%;
min-height: 100svh;
}
.tfa-11 [data-panel] {
interpolate-size: allow-keywords;
}
@supports (interpolate-size: allow-keywords) {
.tfa-11 details::details-content {
height: 0;
overflow: clip;
opacity: 0;
transition: height .4s cubic-bezier(.4,0,.2,1), opacity .32s, content-visibility .4s allow-discrete;
}
.tfa-11 details[open]::details-content {
height: auto;
opacity: 1;
}
}
@media (prefers-reduced-motion: reduce) {
.tfa-11 details::details-content {
transition-duration: 1ms;
}
}Setup — do this once per project
Skip this if your project already runs Tailwind v4.
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>Compiles in the browser — perfect for a CodePen or a quick test, not for production.
npm install tailwindcss @tailwindcss/vite
npm install tailwindcss @tailwindcss/vite// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})Any v4 setup works — Vite, PostCSS or the CLI. Nothing in this demo is bundler-specific.
@import "tailwindcss";
@theme {
--color-tfa11-bg: #f6f7fb;
--color-tfa11-bg: oklch(0.97 0.008 250);
--color-tfa11-ink: #262b38;
--color-tfa11-ink: oklch(0.23 0.03 255);
--color-tfa11-mut: #5e6472;
--color-tfa11-mut: oklch(0.47 0.022 252);
--color-tfa11-edge: #e2e5ee;
--color-tfa11-edge: oklch(0.91 0.012 250);
--color-tfa11-accedge: #8fa6e4;
--color-tfa11-accedge: oklch(0.72 0.1 255);
--color-tfa11-tint: #e9eefb;
--color-tfa11-tint: oklch(0.94 0.028 255);
--color-tfa11-acc: #2f4ec4;
--color-tfa11-acc: oklch(0.47 0.19 260);
--font-tfa11-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--font-tfa11-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tfa-11 {
width: 100%;
min-height: 100svh;
}
.tfa-11 [data-panel] {
interpolate-size: allow-keywords;
}
@supports (interpolate-size: allow-keywords) {
.tfa-11 details::details-content {
height: 0;
overflow: clip;
opacity: 0;
transition: height .4s cubic-bezier(.4,0,.2,1), opacity .32s, content-visibility .4s allow-discrete;
}
.tfa-11 details[open]::details-content {
height: auto;
opacity: 1;
}
}
@media (prefers-reduced-motion: reduce) {
.tfa-11 details::details-content {
transition-duration: 1ms;
}
}@import "tailwindcss";
@theme {
--color-tfa11-bg: #f6f7fb;
--color-tfa11-bg: oklch(0.97 0.008 250);
--color-tfa11-ink: #262b38;
--color-tfa11-ink: oklch(0.23 0.03 255);
--color-tfa11-mut: #5e6472;
--color-tfa11-mut: oklch(0.47 0.022 252);
--color-tfa11-edge: #e2e5ee;
--color-tfa11-edge: oklch(0.91 0.012 250);
--color-tfa11-accedge: #8fa6e4;
--color-tfa11-accedge: oklch(0.72 0.1 255);
--color-tfa11-tint: #e9eefb;
--color-tfa11-tint: oklch(0.94 0.028 255);
--color-tfa11-acc: #2f4ec4;
--color-tfa11-acc: oklch(0.47 0.19 260);
--font-tfa11-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--font-tfa11-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tfa-11 {
width: 100%;
min-height: 100svh;
}
.tfa-11 [data-panel] {
interpolate-size: allow-keywords;
}
@supports (interpolate-size: allow-keywords) {
.tfa-11 details::details-content {
height: 0;
overflow: clip;
opacity: 0;
transition: height .4s cubic-bezier(.4,0,.2,1), opacity .32s, content-visibility .4s allow-discrete;
}
.tfa-11 details[open]::details-content {
height: auto;
opacity: 1;
}
}
@media (prefers-reduced-motion: reduce) {
.tfa-11 details::details-content {
transition-duration: 1ms;
}
}<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- The CSS original kept one shared
--speedtoken so icon and panel could not drift. The utility version statesduration-400on both, which is more repetition but also more local — you see the timing on the element you are reading. If a project has many accordions, promote it back to--ease-*/duration tokens in@theme. - Three icon builds in one demo is where
group-open:proves itself: one variant drives an SVG rotation, a 225° border rotation and a glyph rotation, with no per-build selector anywhere. - UI upgrade from the CSS original: muted copy
oklch(0.5)→0.47, accent0.55→0.47; the chip labels now clear 4.5:1 at 10px, where the original's 10% tint chip did not. - UI upgrade: every icon now also responds to
group-hover:, andmotion-reduce:keeps the colour change instead of killing all feedback — the original's blanket duration override left reduced-motion users with no toggle confirmation at all.
Here's a working CSS demo 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: Tailwind FAQ Chevron Rotate 180 Degrees on Toggle
Source: https://codefronts.com/snippets/tailwind-css-faq-accordion/tailwind-faq-chevron-rotate-180-toggle/
The definitive treatment of the web's most-copied micro-interaction, ported: three chevron builds in one FAQ — inline SVG, a two-border CSS chevron, and a Unicode glyph — each rotating on group-open: with matched timing, plus the UX rules for which way a closed chevron should point and why the rotation duration must equal the panel's.
## HTML
```html
<section class="tfa-11 w-full min-h-svh grid place-items-center bg-tfa11-bg font-tfa11-sans text-tfa11-ink px-5 py-12">
<div class="w-[min(680px,100%)]">
<header>
<h1 class="text-[clamp(28px,5vw,40px)] font-extrabold leading-[1.08] tracking-[-0.025em]">The 180° chevron, three ways</h1>
<p class="mt-3 max-w-[56ch] text-[15px] leading-relaxed text-tfa11-mut">Same rotation, three icon builds — SVG, pure CSS borders, Unicode. Matched <code class="rounded bg-tfa11-tint px-1.5 py-0.5 font-tfa11-mono text-[0.87em] text-tfa11-acc">duration-400</code> keeps icon and panel in sync.</p>
</header>
<div data-panel class="mt-8 flex flex-col gap-2.5">
<details class="group rounded-2xl border border-tfa11-edge bg-white shadow-[0_2px_8px_oklch(0.4_0.05_250/0.05)] transition-[border-color,box-shadow] duration-300 open:border-tfa11-accedge open:shadow-[0_14px_34px_-20px_oklch(0.45_0.14_250/0.4)]" open>
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3 px-5 py-4 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa11-acc focus-visible:rounded-2xl focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa11-acc [&::-webkit-details-marker]:hidden">
<span class="shrink-0 rounded-md bg-tfa11-tint px-2 py-1 font-tfa11-mono text-[10px] font-bold tracking-[0.05em] text-tfa11-acc">A · SVG</span>Which icon build should production use?
<span aria-hidden="true" class="ml-auto grid shrink-0 place-items-center text-tfa11-mut transition-[rotate,color] duration-400 ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:text-tfa11-acc group-open:rotate-180 group-open:text-tfa11-acc motion-reduce:transition-colors"><svg viewBox="0 0 16 16" width="16" height="16"><path d="M3 6l5 5 5-5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
</summary>
<p class="max-w-[60ch] px-5 pb-4 text-[14px] leading-[1.7] text-tfa11-mut">This one. <code class="rounded bg-tfa11-tint px-1.5 py-0.5 font-tfa11-mono text-[0.87em] text-tfa11-acc">stroke: currentColor</code> inherits your text colour automatically, the rounded caps stay crisp at every DPI, and rotating the whole SVG element avoids every alignment quirk the other two builds carry.</p>
</details>
<details class="group rounded-2xl border border-tfa11-edge bg-white shadow-[0_2px_8px_oklch(0.4_0.05_250/0.05)] transition-[border-color,box-shadow] duration-300 open:border-tfa11-accedge open:shadow-[0_14px_34px_-20px_oklch(0.45_0.14_250/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3 px-5 py-4 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa11-acc focus-visible:rounded-2xl focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa11-acc [&::-webkit-details-marker]:hidden">
<span class="shrink-0 rounded-md bg-tfa11-tint px-2 py-1 font-tfa11-mono text-[10px] font-bold tracking-[0.05em] text-tfa11-acc">B · borders</span>How does the zero-asset chevron work?
<span aria-hidden="true" class="ml-auto size-2.5 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa11-mut transition-[rotate,translate,border-color] duration-400 ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:border-tfa11-acc group-open:translate-y-0.5 group-open:rotate-[225deg] group-open:border-tfa11-acc motion-reduce:transition-colors"></span>
</summary>
<p class="max-w-[60ch] px-5 pb-4 text-[14px] leading-[1.7] text-tfa11-mut">A 9px square with only its right and bottom borders, pre-rotated 45° — so “rotate 180°” actually means <code class="rounded bg-tfa11-tint px-1.5 py-0.5 font-tfa11-mono text-[0.87em] text-tfa11-acc">rotate-[225deg]</code>, and a 2px translate nudge re-centres its optical middle. Zero assets, two gotchas.</p>
</details>
<details class="group rounded-2xl border border-tfa11-edge bg-white shadow-[0_2px_8px_oklch(0.4_0.05_250/0.05)] transition-[border-color,box-shadow] duration-300 open:border-tfa11-accedge open:shadow-[0_14px_34px_-20px_oklch(0.45_0.14_250/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3 px-5 py-4 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa11-acc focus-visible:rounded-2xl focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa11-acc [&::-webkit-details-marker]:hidden">
<span class="shrink-0 rounded-md bg-tfa11-tint px-2 py-1 font-tfa11-mono text-[10px] font-bold tracking-[0.05em] text-tfa11-acc">C · Unicode</span>When is a text arrow good enough?
<span aria-hidden="true" class="ml-auto shrink-0 -translate-y-0.5 text-[18px] font-bold leading-none text-tfa11-mut transition-[rotate,translate,color] duration-400 ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:text-tfa11-acc group-open:translate-y-0.5 group-open:rotate-180 group-open:text-tfa11-acc motion-reduce:transition-colors">⌄</span>
</summary>
<p class="max-w-[60ch] px-5 pb-4 text-[14px] leading-[1.7] text-tfa11-mut">Prototypes and plain-text contexts. It costs one character, but its baseline position depends on the font stack — explicit sizing and <code class="rounded bg-tfa11-tint px-1.5 py-0.5 font-tfa11-mono text-[0.87em] text-tfa11-acc">leading-none</code> tame it, mostly. Ship SVG when it matters.</p>
</details>
<details class="group rounded-2xl border border-tfa11-edge bg-white shadow-[0_2px_8px_oklch(0.4_0.05_250/0.05)] transition-[border-color,box-shadow] duration-300 open:border-tfa11-accedge open:shadow-[0_14px_34px_-20px_oklch(0.45_0.14_250/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3 px-5 py-4 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa11-acc focus-visible:rounded-2xl focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa11-acc [&::-webkit-details-marker]:hidden">
<span class="shrink-0 rounded-md bg-tfa11-tint px-2 py-1 font-tfa11-mono text-[10px] font-bold tracking-[0.05em] text-tfa11-acc">UX</span>Which way should a closed chevron point?
<span aria-hidden="true" class="ml-auto grid shrink-0 place-items-center text-tfa11-mut transition-[rotate,color] duration-400 ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:text-tfa11-acc group-open:rotate-180 group-open:text-tfa11-acc motion-reduce:transition-colors"><svg viewBox="0 0 16 16" width="16" height="16"><path d="M3 6l5 5 5-5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
</summary>
<p class="max-w-[60ch] px-5 pb-4 text-[14px] leading-[1.7] text-tfa11-mut">Down when closed (content continues below), up when open. Right-pointing chevrons signal navigation into another screen — using one on an accordion misleads screen-magnifier and low-vision users especially. And match the rotation duration to the panel, or mismatched timings read as jank.</p>
</details>
</div>
<p class="mt-6 text-[12.5px] text-tfa11-mut">All three rotate under <code class="rounded bg-tfa11-tint px-1.5 py-0.5 font-tfa11-mono text-[0.87em] text-tfa11-acc">group-open:</code> — build B to 225°, because it starts at 45°.</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tfa11-bg: #f6f7fb;
--color-tfa11-bg: oklch(0.97 0.008 250);
--color-tfa11-ink: #262b38;
--color-tfa11-ink: oklch(0.23 0.03 255);
--color-tfa11-mut: #5e6472;
--color-tfa11-mut: oklch(0.47 0.022 252);
--color-tfa11-edge: #e2e5ee;
--color-tfa11-edge: oklch(0.91 0.012 250);
--color-tfa11-accedge: #8fa6e4;
--color-tfa11-accedge: oklch(0.72 0.1 255);
--color-tfa11-tint: #e9eefb;
--color-tfa11-tint: oklch(0.94 0.028 255);
--color-tfa11-acc: #2f4ec4;
--color-tfa11-acc: oklch(0.47 0.19 260);
--font-tfa11-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--font-tfa11-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tfa-11 {
width: 100%;
min-height: 100svh;
}
.tfa-11 [data-panel] {
interpolate-size: allow-keywords;
}
@supports (interpolate-size: allow-keywords) {
.tfa-11 details::details-content {
height: 0;
overflow: clip;
opacity: 0;
transition: height .4s cubic-bezier(.4,0,.2,1), opacity .32s, content-visibility .4s allow-discrete;
}
.tfa-11 details[open]::details-content {
height: auto;
opacity: 1;
}
}
@media (prefers-reduced-motion: reduce) {
.tfa-11 details::details-content {
transition-duration: 1ms;
}
}
```Here's a working CSS demo 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: Tailwind FAQ Chevron Rotate 180 Degrees on Toggle
Source: https://codefronts.com/snippets/tailwind-css-faq-accordion/tailwind-faq-chevron-rotate-180-toggle/
The definitive treatment of the web's most-copied micro-interaction, ported: three chevron builds in one FAQ — inline SVG, a two-border CSS chevron, and a Unicode glyph — each rotating on group-open: with matched timing, plus the UX rules for which way a closed chevron should point and why the rotation duration must equal the panel's.
## HTML
```html
<section class="tfa-11 w-full min-h-svh grid place-items-center bg-tfa11-bg font-tfa11-sans text-tfa11-ink px-5 py-12">
<div class="w-[min(680px,100%)]">
<header>
<h1 class="text-[clamp(28px,5vw,40px)] font-extrabold leading-[1.08] tracking-[-0.025em]">The 180° chevron, three ways</h1>
<p class="mt-3 max-w-[56ch] text-[15px] leading-relaxed text-tfa11-mut">Same rotation, three icon builds — SVG, pure CSS borders, Unicode. Matched <code class="rounded bg-tfa11-tint px-1.5 py-0.5 font-tfa11-mono text-[0.87em] text-tfa11-acc">duration-400</code> keeps icon and panel in sync.</p>
</header>
<div data-panel class="mt-8 flex flex-col gap-2.5">
<details class="group rounded-2xl border border-tfa11-edge bg-white shadow-[0_2px_8px_oklch(0.4_0.05_250/0.05)] transition-[border-color,box-shadow] duration-300 open:border-tfa11-accedge open:shadow-[0_14px_34px_-20px_oklch(0.45_0.14_250/0.4)]" open>
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3 px-5 py-4 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa11-acc focus-visible:rounded-2xl focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa11-acc [&::-webkit-details-marker]:hidden">
<span class="shrink-0 rounded-md bg-tfa11-tint px-2 py-1 font-tfa11-mono text-[10px] font-bold tracking-[0.05em] text-tfa11-acc">A · SVG</span>Which icon build should production use?
<span aria-hidden="true" class="ml-auto grid shrink-0 place-items-center text-tfa11-mut transition-[rotate,color] duration-400 ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:text-tfa11-acc group-open:rotate-180 group-open:text-tfa11-acc motion-reduce:transition-colors"><svg viewBox="0 0 16 16" width="16" height="16"><path d="M3 6l5 5 5-5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
</summary>
<p class="max-w-[60ch] px-5 pb-4 text-[14px] leading-[1.7] text-tfa11-mut">This one. <code class="rounded bg-tfa11-tint px-1.5 py-0.5 font-tfa11-mono text-[0.87em] text-tfa11-acc">stroke: currentColor</code> inherits your text colour automatically, the rounded caps stay crisp at every DPI, and rotating the whole SVG element avoids every alignment quirk the other two builds carry.</p>
</details>
<details class="group rounded-2xl border border-tfa11-edge bg-white shadow-[0_2px_8px_oklch(0.4_0.05_250/0.05)] transition-[border-color,box-shadow] duration-300 open:border-tfa11-accedge open:shadow-[0_14px_34px_-20px_oklch(0.45_0.14_250/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3 px-5 py-4 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa11-acc focus-visible:rounded-2xl focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa11-acc [&::-webkit-details-marker]:hidden">
<span class="shrink-0 rounded-md bg-tfa11-tint px-2 py-1 font-tfa11-mono text-[10px] font-bold tracking-[0.05em] text-tfa11-acc">B · borders</span>How does the zero-asset chevron work?
<span aria-hidden="true" class="ml-auto size-2.5 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa11-mut transition-[rotate,translate,border-color] duration-400 ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:border-tfa11-acc group-open:translate-y-0.5 group-open:rotate-[225deg] group-open:border-tfa11-acc motion-reduce:transition-colors"></span>
</summary>
<p class="max-w-[60ch] px-5 pb-4 text-[14px] leading-[1.7] text-tfa11-mut">A 9px square with only its right and bottom borders, pre-rotated 45° — so “rotate 180°” actually means <code class="rounded bg-tfa11-tint px-1.5 py-0.5 font-tfa11-mono text-[0.87em] text-tfa11-acc">rotate-[225deg]</code>, and a 2px translate nudge re-centres its optical middle. Zero assets, two gotchas.</p>
</details>
<details class="group rounded-2xl border border-tfa11-edge bg-white shadow-[0_2px_8px_oklch(0.4_0.05_250/0.05)] transition-[border-color,box-shadow] duration-300 open:border-tfa11-accedge open:shadow-[0_14px_34px_-20px_oklch(0.45_0.14_250/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3 px-5 py-4 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa11-acc focus-visible:rounded-2xl focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa11-acc [&::-webkit-details-marker]:hidden">
<span class="shrink-0 rounded-md bg-tfa11-tint px-2 py-1 font-tfa11-mono text-[10px] font-bold tracking-[0.05em] text-tfa11-acc">C · Unicode</span>When is a text arrow good enough?
<span aria-hidden="true" class="ml-auto shrink-0 -translate-y-0.5 text-[18px] font-bold leading-none text-tfa11-mut transition-[rotate,translate,color] duration-400 ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:text-tfa11-acc group-open:translate-y-0.5 group-open:rotate-180 group-open:text-tfa11-acc motion-reduce:transition-colors">⌄</span>
</summary>
<p class="max-w-[60ch] px-5 pb-4 text-[14px] leading-[1.7] text-tfa11-mut">Prototypes and plain-text contexts. It costs one character, but its baseline position depends on the font stack — explicit sizing and <code class="rounded bg-tfa11-tint px-1.5 py-0.5 font-tfa11-mono text-[0.87em] text-tfa11-acc">leading-none</code> tame it, mostly. Ship SVG when it matters.</p>
</details>
<details class="group rounded-2xl border border-tfa11-edge bg-white shadow-[0_2px_8px_oklch(0.4_0.05_250/0.05)] transition-[border-color,box-shadow] duration-300 open:border-tfa11-accedge open:shadow-[0_14px_34px_-20px_oklch(0.45_0.14_250/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3 px-5 py-4 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa11-acc focus-visible:rounded-2xl focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa11-acc [&::-webkit-details-marker]:hidden">
<span class="shrink-0 rounded-md bg-tfa11-tint px-2 py-1 font-tfa11-mono text-[10px] font-bold tracking-[0.05em] text-tfa11-acc">UX</span>Which way should a closed chevron point?
<span aria-hidden="true" class="ml-auto grid shrink-0 place-items-center text-tfa11-mut transition-[rotate,color] duration-400 ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:text-tfa11-acc group-open:rotate-180 group-open:text-tfa11-acc motion-reduce:transition-colors"><svg viewBox="0 0 16 16" width="16" height="16"><path d="M3 6l5 5 5-5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
</summary>
<p class="max-w-[60ch] px-5 pb-4 text-[14px] leading-[1.7] text-tfa11-mut">Down when closed (content continues below), up when open. Right-pointing chevrons signal navigation into another screen — using one on an accordion misleads screen-magnifier and low-vision users especially. And match the rotation duration to the panel, or mismatched timings read as jank.</p>
</details>
</div>
<p class="mt-6 text-[12.5px] text-tfa11-mut">All three rotate under <code class="rounded bg-tfa11-tint px-1.5 py-0.5 font-tfa11-mono text-[0.87em] text-tfa11-acc">group-open:</code> — build B to 225°, because it starts at 45°.</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tfa11-bg: #f6f7fb;
--color-tfa11-bg: oklch(0.97 0.008 250);
--color-tfa11-ink: #262b38;
--color-tfa11-ink: oklch(0.23 0.03 255);
--color-tfa11-mut: #5e6472;
--color-tfa11-mut: oklch(0.47 0.022 252);
--color-tfa11-edge: #e2e5ee;
--color-tfa11-edge: oklch(0.91 0.012 250);
--color-tfa11-accedge: #8fa6e4;
--color-tfa11-accedge: oklch(0.72 0.1 255);
--color-tfa11-tint: #e9eefb;
--color-tfa11-tint: oklch(0.94 0.028 255);
--color-tfa11-acc: #2f4ec4;
--color-tfa11-acc: oklch(0.47 0.19 260);
--font-tfa11-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--font-tfa11-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tfa-11 {
width: 100%;
min-height: 100svh;
}
.tfa-11 [data-panel] {
interpolate-size: allow-keywords;
}
@supports (interpolate-size: allow-keywords) {
.tfa-11 details::details-content {
height: 0;
overflow: clip;
opacity: 0;
transition: height .4s cubic-bezier(.4,0,.2,1), opacity .32s, content-visibility .4s allow-discrete;
}
.tfa-11 details[open]::details-content {
height: auto;
opacity: 1;
}
}
@media (prefers-reduced-motion: reduce) {
.tfa-11 details::details-content {
transition-duration: 1ms;
}
}
```How this works
One variant, three icon builds. The SVG rotates as a whole element and is the production choice: stroke="currentColor" inherits the text colour, rounded caps stay crisp at any DPI, and there are no alignment quirks.
The CSS build is a 9px square with only right and bottom borders, pre-rotated 45°. That pre-rotation is why open means rotate-[225deg] rather than 180, and why it needs a 2px translate-y nudge to re-centre optically. The Unicode glyph costs one character but its baseline depends on the font stack — prototypes only.
Why the individual properties matter. Tailwind's rotate-* and translate-* compile to the individual rotate/translate properties in v4, so they compose instead of fighting — the classic transform overwrote my centring bug cannot happen here. Name them in the transition list and each keeps its own timing.
UX rules worth stealing: closed points down (content continues below), open points up. Right-pointing chevrons signal navigation into another screen, which misleads screen-magnifier users especially. And the rotation duration must equal the panel's height duration — a 200ms flick over a 400ms panel reads as broken, which is why both are duration-400 here.
Make it yours
- A 270° twirl:
group-open:rotate-[270deg]adds playfulness — keep it under 300ms or it upstages the content. - Colour shift on open: already wired (
group-open:text-tfa11-acc) — state reads in peripheral vision. - Circle-chip chevron: wrap the SVG in a bordered
size-8ring (demo 02 does this) for a stronger hit-target affordance. - Timing: change the two
duration-400values together — icon and panel must agree.
Gotchas — read before shipping
- Rotating a border-built chevron from 45° means going to 225°, not 180°. SVG avoids this entire class of bug.
- Keep the chevron out of the text flow (
ml-auto+shrink-0), or long questions wrap under it. aria-hidden="true"on the icon always —<details>already announces the state; a decorative arrow must not be read out.transition-transformwithout aduration-*uses the 150ms default, which reads as a glitch.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 129+ | not yet | not yet | 129+ |
Floor set by oklch(), interpolate-size as this demo is written. The core technique itself goes back further — Chrome 111+.
Individual transform properties are 2022-settled everywhere; the rest is universal <details> plus transitions. The floor is Tailwind v4's generated sheet.