03 / 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 Exclusive Accordion — Only One FAQ Open at a Time
Only-one-open used to mean JavaScript closing siblings; now it is one HTML attribute. Give every <details> the same name and the browser enforces exclusivity like radio buttons. The port's contribution is the attention choreography: has-[details[open]]: on the list dims the closed questions, which is :has() written where you can see it.
Complete Tailwind CSS landing page templates in HTML, React, Next.js and Vue · from $49
Cruip · Affiliate link
The code
<section class="tfa-03 w-full min-h-svh grid place-items-center bg-tfa03-bg font-tfa03-sans text-tfa03-ink px-5 py-12 bg-[linear-gradient(180deg,var(--color-tfa03-wash),var(--color-tfa03-bg)_42%)]">
<div class="w-[min(680px,100%)]">
<header>
<span class="inline-block rounded-full bg-tfa03-tint px-3 py-1.5 font-tfa03-mono text-[11.5px] font-semibold text-tfa03-acc">name="faq" · zero-JS exclusivity</span>
<h1 class="mt-4 text-[clamp(28px,5vw,40px)] font-extrabold leading-[1.08] tracking-[-0.025em]">Pricing questions, answered</h1>
<p class="mt-3 max-w-[54ch] text-[15px] leading-relaxed text-tfa03-mut">Open any question — the browser closes the previous one. One attribute, no JavaScript.</p>
</header>
<div data-panel class="mt-8 flex flex-col gap-2.5 has-[details[open]]:[&>details:not([open])]:opacity-70">
<details name="tfa03-faq" class="group relative overflow-hidden rounded-2xl border border-tfa03-edge bg-white transition-[border-color,box-shadow,opacity] duration-300 open:border-tfa03-accedge open:shadow-[0_14px_34px_-18px_oklch(0.45_0.14_275/0.35)]" open>
<span aria-hidden="true" class="absolute inset-y-0 left-0 w-[3px] origin-top scale-y-0 bg-tfa03-acc transition-transform duration-350 ease-[cubic-bezier(0.4,0,0.2,1)] group-open:scale-y-100 motion-reduce:transition-none"></span>
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3.5 px-5 py-4 text-[15.5px] font-semibold transition-colors duration-200 hover:text-tfa03-acc focus-visible:rounded-2xl focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa03-acc [&::-webkit-details-marker]:hidden">
<span class="font-tfa03-mono text-[11px] font-bold text-tfa03-acc">01</span>Is there a free plan?
<i aria-hidden="true" class="ml-auto size-2.5 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa03-mut transition-[rotate,translate,border-color] duration-350 group-hover:border-tfa03-acc group-open:translate-y-0.5 group-open:rotate-[225deg] group-open:border-tfa03-acc motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[58ch] pb-4 pl-12 pr-5 text-[14.5px] leading-[1.7] text-tfa03-mut">Yes — free forever for up to 3 projects and 2 seats, with no card required. It is a real plan, not a trial: teams ship production work on it every day.</p>
</details>
<details name="tfa03-faq" class="group relative overflow-hidden rounded-2xl border border-tfa03-edge bg-white transition-[border-color,box-shadow,opacity] duration-300 open:border-tfa03-accedge open:shadow-[0_14px_34px_-18px_oklch(0.45_0.14_275/0.35)]">
<span aria-hidden="true" class="absolute inset-y-0 left-0 w-[3px] origin-top scale-y-0 bg-tfa03-acc transition-transform duration-350 ease-[cubic-bezier(0.4,0,0.2,1)] group-open:scale-y-100 motion-reduce:transition-none"></span>
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3.5 px-5 py-4 text-[15.5px] font-semibold transition-colors duration-200 hover:text-tfa03-acc focus-visible:rounded-2xl focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa03-acc [&::-webkit-details-marker]:hidden">
<span class="font-tfa03-mono text-[11px] font-bold text-tfa03-acc">02</span>What counts as a “seat”?
<i aria-hidden="true" class="ml-auto size-2.5 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa03-mut transition-[rotate,translate,border-color] duration-350 group-hover:border-tfa03-acc group-open:translate-y-0.5 group-open:rotate-[225deg] group-open:border-tfa03-acc motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[58ch] pb-4 pl-12 pr-5 text-[14.5px] leading-[1.7] text-tfa03-mut">Anyone who can edit. Viewers and commenters are unlimited and free on every plan — you only pay for people who change things.</p>
</details>
<details name="tfa03-faq" class="group relative overflow-hidden rounded-2xl border border-tfa03-edge bg-white transition-[border-color,box-shadow,opacity] duration-300 open:border-tfa03-accedge open:shadow-[0_14px_34px_-18px_oklch(0.45_0.14_275/0.35)]">
<span aria-hidden="true" class="absolute inset-y-0 left-0 w-[3px] origin-top scale-y-0 bg-tfa03-acc transition-transform duration-350 ease-[cubic-bezier(0.4,0,0.2,1)] group-open:scale-y-100 motion-reduce:transition-none"></span>
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3.5 px-5 py-4 text-[15.5px] font-semibold transition-colors duration-200 hover:text-tfa03-acc focus-visible:rounded-2xl focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa03-acc [&::-webkit-details-marker]:hidden">
<span class="font-tfa03-mono text-[11px] font-bold text-tfa03-acc">03</span>Do prices include tax?
<i aria-hidden="true" class="ml-auto size-2.5 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa03-mut transition-[rotate,translate,border-color] duration-350 group-hover:border-tfa03-acc group-open:translate-y-0.5 group-open:rotate-[225deg] group-open:border-tfa03-acc motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[58ch] pb-4 pl-12 pr-5 text-[14.5px] leading-[1.7] text-tfa03-mut">Prices are shown pre-tax; VAT/GST is added at checkout based on your billing country. US customers see applicable state sales tax, and every invoice is compliant for expensing.</p>
</details>
<details name="tfa03-faq" class="group relative overflow-hidden rounded-2xl border border-tfa03-edge bg-white transition-[border-color,box-shadow,opacity] duration-300 open:border-tfa03-accedge open:shadow-[0_14px_34px_-18px_oklch(0.45_0.14_275/0.35)]">
<span aria-hidden="true" class="absolute inset-y-0 left-0 w-[3px] origin-top scale-y-0 bg-tfa03-acc transition-transform duration-350 ease-[cubic-bezier(0.4,0,0.2,1)] group-open:scale-y-100 motion-reduce:transition-none"></span>
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3.5 px-5 py-4 text-[15.5px] font-semibold transition-colors duration-200 hover:text-tfa03-acc focus-visible:rounded-2xl focus-visible:-outline-offset-2 focus-visible:outline-2 focus-visible:outline-tfa03-acc [&::-webkit-details-marker]:hidden">
<span class="font-tfa03-mono text-[11px] font-bold text-tfa03-acc">04</span>Can I pay by invoice?
<i aria-hidden="true" class="ml-auto size-2.5 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa03-mut transition-[rotate,translate,border-color] duration-350 group-hover:border-tfa03-acc group-open:translate-y-0.5 group-open:rotate-[225deg] group-open:border-tfa03-acc motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[58ch] pb-4 pl-12 pr-5 text-[14.5px] leading-[1.7] text-tfa03-mut">Annual plans over $2,000 can be paid by bank transfer with NET-30 terms. Contact sales and we will set up procurement, security review and a countersigned DPA if you need one.</p>
</details>
</div>
<p class="mt-6 text-[12.5px] text-tfa03-mut">Closed questions dim via <code class="rounded bg-tfa03-tint px-1.5 py-0.5 font-tfa03-mono text-[0.88em] text-tfa03-acc">has-[details[open]]:</code> — attention follows the open panel.</p>
</div>
</section><section class="tfa-03 w-full min-h-svh grid place-items-center bg-tfa03-bg font-tfa03-sans text-tfa03-ink px-5 py-12 bg-[linear-gradient(180deg,var(--color-tfa03-wash),var(--color-tfa03-bg)_42%)]">
<div class="w-[min(680px,100%)]">
<header>
<span class="inline-block rounded-full bg-tfa03-tint px-3 py-1.5 font-tfa03-mono text-[11.5px] font-semibold text-tfa03-acc">name="faq" · zero-JS exclusivity</span>
<h1 class="mt-4 text-[clamp(28px,5vw,40px)] font-extrabold leading-[1.08] tracking-[-0.025em]">Pricing questions, answered</h1>
<p class="mt-3 max-w-[54ch] text-[15px] leading-relaxed text-tfa03-mut">Open any question — the browser closes the previous one. One attribute, no JavaScript.</p>
</header>
<div data-panel class="mt-8 flex flex-col gap-2.5 has-[details[open]]:[&>details:not([open])]:opacity-70">
<details name="tfa03-faq" class="group relative overflow-hidden rounded-2xl border border-tfa03-edge bg-white transition-[border-color,box-shadow,opacity] duration-300 open:border-tfa03-accedge open:shadow-[0_14px_34px_-18px_oklch(0.45_0.14_275/0.35)]" open>
<span aria-hidden="true" class="absolute inset-y-0 left-0 w-[3px] origin-top scale-y-0 bg-tfa03-acc transition-transform duration-350 ease-[cubic-bezier(0.4,0,0.2,1)] group-open:scale-y-100 motion-reduce:transition-none"></span>
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3.5 px-5 py-4 text-[15.5px] font-semibold transition-colors duration-200 hover:text-tfa03-acc focus-visible:rounded-2xl focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa03-acc [&::-webkit-details-marker]:hidden">
<span class="font-tfa03-mono text-[11px] font-bold text-tfa03-acc">01</span>Is there a free plan?
<i aria-hidden="true" class="ml-auto size-2.5 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa03-mut transition-[rotate,translate,border-color] duration-350 group-hover:border-tfa03-acc group-open:translate-y-0.5 group-open:rotate-[225deg] group-open:border-tfa03-acc motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[58ch] pb-4 pl-12 pr-5 text-[14.5px] leading-[1.7] text-tfa03-mut">Yes — free forever for up to 3 projects and 2 seats, with no card required. It is a real plan, not a trial: teams ship production work on it every day.</p>
</details>
<details name="tfa03-faq" class="group relative overflow-hidden rounded-2xl border border-tfa03-edge bg-white transition-[border-color,box-shadow,opacity] duration-300 open:border-tfa03-accedge open:shadow-[0_14px_34px_-18px_oklch(0.45_0.14_275/0.35)]">
<span aria-hidden="true" class="absolute inset-y-0 left-0 w-[3px] origin-top scale-y-0 bg-tfa03-acc transition-transform duration-350 ease-[cubic-bezier(0.4,0,0.2,1)] group-open:scale-y-100 motion-reduce:transition-none"></span>
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3.5 px-5 py-4 text-[15.5px] font-semibold transition-colors duration-200 hover:text-tfa03-acc focus-visible:rounded-2xl focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa03-acc [&::-webkit-details-marker]:hidden">
<span class="font-tfa03-mono text-[11px] font-bold text-tfa03-acc">02</span>What counts as a “seat”?
<i aria-hidden="true" class="ml-auto size-2.5 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa03-mut transition-[rotate,translate,border-color] duration-350 group-hover:border-tfa03-acc group-open:translate-y-0.5 group-open:rotate-[225deg] group-open:border-tfa03-acc motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[58ch] pb-4 pl-12 pr-5 text-[14.5px] leading-[1.7] text-tfa03-mut">Anyone who can edit. Viewers and commenters are unlimited and free on every plan — you only pay for people who change things.</p>
</details>
<details name="tfa03-faq" class="group relative overflow-hidden rounded-2xl border border-tfa03-edge bg-white transition-[border-color,box-shadow,opacity] duration-300 open:border-tfa03-accedge open:shadow-[0_14px_34px_-18px_oklch(0.45_0.14_275/0.35)]">
<span aria-hidden="true" class="absolute inset-y-0 left-0 w-[3px] origin-top scale-y-0 bg-tfa03-acc transition-transform duration-350 ease-[cubic-bezier(0.4,0,0.2,1)] group-open:scale-y-100 motion-reduce:transition-none"></span>
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3.5 px-5 py-4 text-[15.5px] font-semibold transition-colors duration-200 hover:text-tfa03-acc focus-visible:rounded-2xl focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa03-acc [&::-webkit-details-marker]:hidden">
<span class="font-tfa03-mono text-[11px] font-bold text-tfa03-acc">03</span>Do prices include tax?
<i aria-hidden="true" class="ml-auto size-2.5 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa03-mut transition-[rotate,translate,border-color] duration-350 group-hover:border-tfa03-acc group-open:translate-y-0.5 group-open:rotate-[225deg] group-open:border-tfa03-acc motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[58ch] pb-4 pl-12 pr-5 text-[14.5px] leading-[1.7] text-tfa03-mut">Prices are shown pre-tax; VAT/GST is added at checkout based on your billing country. US customers see applicable state sales tax, and every invoice is compliant for expensing.</p>
</details>
<details name="tfa03-faq" class="group relative overflow-hidden rounded-2xl border border-tfa03-edge bg-white transition-[border-color,box-shadow,opacity] duration-300 open:border-tfa03-accedge open:shadow-[0_14px_34px_-18px_oklch(0.45_0.14_275/0.35)]">
<span aria-hidden="true" class="absolute inset-y-0 left-0 w-[3px] origin-top scale-y-0 bg-tfa03-acc transition-transform duration-350 ease-[cubic-bezier(0.4,0,0.2,1)] group-open:scale-y-100 motion-reduce:transition-none"></span>
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3.5 px-5 py-4 text-[15.5px] font-semibold transition-colors duration-200 hover:text-tfa03-acc focus-visible:rounded-2xl focus-visible:-outline-offset-2 focus-visible:outline-2 focus-visible:outline-tfa03-acc [&::-webkit-details-marker]:hidden">
<span class="font-tfa03-mono text-[11px] font-bold text-tfa03-acc">04</span>Can I pay by invoice?
<i aria-hidden="true" class="ml-auto size-2.5 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa03-mut transition-[rotate,translate,border-color] duration-350 group-hover:border-tfa03-acc group-open:translate-y-0.5 group-open:rotate-[225deg] group-open:border-tfa03-acc motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[58ch] pb-4 pl-12 pr-5 text-[14.5px] leading-[1.7] text-tfa03-mut">Annual plans over $2,000 can be paid by bank transfer with NET-30 terms. Contact sales and we will set up procurement, security review and a countersigned DPA if you need one.</p>
</details>
</div>
<p class="mt-6 text-[12.5px] text-tfa03-mut">Closed questions dim via <code class="rounded bg-tfa03-tint px-1.5 py-0.5 font-tfa03-mono text-[0.88em] text-tfa03-acc">has-[details[open]]:</code> — attention follows the open panel.</p>
</div>
</section>@import "tailwindcss";
@theme {
--color-tfa03-bg: #fafafd;
--color-tfa03-bg: oklch(0.98 0.005 270);
--color-tfa03-wash: #eeecfb;
--color-tfa03-wash: oklch(0.94 0.025 275);
--color-tfa03-ink: #1f1d2b;
--color-tfa03-ink: oklch(0.22 0.03 275);
--color-tfa03-mut: #5c5a6e;
--color-tfa03-mut: oklch(0.48 0.025 275);
--color-tfa03-edge: #e3e1ee;
--color-tfa03-edge: oklch(0.91 0.012 275);
--color-tfa03-accedge: #9b8ce0;
--color-tfa03-accedge: oklch(0.72 0.1 285);
--color-tfa03-tint: #eeebfd;
--color-tfa03-tint: oklch(0.94 0.03 285);
--color-tfa03-acc: #5b3fd0;
--color-tfa03-acc: oklch(0.47 0.2 285);
--font-tfa03-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--font-tfa03-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tfa-03 {
width: 100%;
min-height: 100svh;
}
/* Same irreducible four lines as demo 02 — the animated panel, once, for the whole list. */
.tfa-03 [data-panel] {
interpolate-size: allow-keywords;
}
@supports (interpolate-size: allow-keywords) {
.tfa-03 details::details-content {
height: 0;
overflow: clip;
opacity: 0;
transition: height .38s cubic-bezier(.4,0,.2,1), opacity .3s, content-visibility .38s allow-discrete;
}
.tfa-03 details[open]::details-content {
height: auto;
opacity: 1;
}
}
@media (prefers-reduced-motion: reduce) {
.tfa-03 details::details-content {
transition-duration: 1ms;
}
}@import "tailwindcss";
@theme {
--color-tfa03-bg: #fafafd;
--color-tfa03-bg: oklch(0.98 0.005 270);
--color-tfa03-wash: #eeecfb;
--color-tfa03-wash: oklch(0.94 0.025 275);
--color-tfa03-ink: #1f1d2b;
--color-tfa03-ink: oklch(0.22 0.03 275);
--color-tfa03-mut: #5c5a6e;
--color-tfa03-mut: oklch(0.48 0.025 275);
--color-tfa03-edge: #e3e1ee;
--color-tfa03-edge: oklch(0.91 0.012 275);
--color-tfa03-accedge: #9b8ce0;
--color-tfa03-accedge: oklch(0.72 0.1 285);
--color-tfa03-tint: #eeebfd;
--color-tfa03-tint: oklch(0.94 0.03 285);
--color-tfa03-acc: #5b3fd0;
--color-tfa03-acc: oklch(0.47 0.2 285);
--font-tfa03-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--font-tfa03-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tfa-03 {
width: 100%;
min-height: 100svh;
}
/* Same irreducible four lines as demo 02 — the animated panel, once, for the whole list. */
.tfa-03 [data-panel] {
interpolate-size: allow-keywords;
}
@supports (interpolate-size: allow-keywords) {
.tfa-03 details::details-content {
height: 0;
overflow: clip;
opacity: 0;
transition: height .38s cubic-bezier(.4,0,.2,1), opacity .3s, content-visibility .38s allow-discrete;
}
.tfa-03 details[open]::details-content {
height: auto;
opacity: 1;
}
}
@media (prefers-reduced-motion: reduce) {
.tfa-03 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-tfa03-bg: #fafafd;
--color-tfa03-bg: oklch(0.98 0.005 270);
--color-tfa03-wash: #eeecfb;
--color-tfa03-wash: oklch(0.94 0.025 275);
--color-tfa03-ink: #1f1d2b;
--color-tfa03-ink: oklch(0.22 0.03 275);
--color-tfa03-mut: #5c5a6e;
--color-tfa03-mut: oklch(0.48 0.025 275);
--color-tfa03-edge: #e3e1ee;
--color-tfa03-edge: oklch(0.91 0.012 275);
--color-tfa03-accedge: #9b8ce0;
--color-tfa03-accedge: oklch(0.72 0.1 285);
--color-tfa03-tint: #eeebfd;
--color-tfa03-tint: oklch(0.94 0.03 285);
--color-tfa03-acc: #5b3fd0;
--color-tfa03-acc: oklch(0.47 0.2 285);
--font-tfa03-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--font-tfa03-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tfa-03 {
width: 100%;
min-height: 100svh;
}
/* Same irreducible four lines as demo 02 — the animated panel, once, for the whole list. */
.tfa-03 [data-panel] {
interpolate-size: allow-keywords;
}
@supports (interpolate-size: allow-keywords) {
.tfa-03 details::details-content {
height: 0;
overflow: clip;
opacity: 0;
transition: height .38s cubic-bezier(.4,0,.2,1), opacity .3s, content-visibility .38s allow-discrete;
}
.tfa-03 details[open]::details-content {
height: auto;
opacity: 1;
}
}
@media (prefers-reduced-motion: reduce) {
.tfa-03 details::details-content {
transition-duration: 1ms;
}
}@import "tailwindcss";
@theme {
--color-tfa03-bg: #fafafd;
--color-tfa03-bg: oklch(0.98 0.005 270);
--color-tfa03-wash: #eeecfb;
--color-tfa03-wash: oklch(0.94 0.025 275);
--color-tfa03-ink: #1f1d2b;
--color-tfa03-ink: oklch(0.22 0.03 275);
--color-tfa03-mut: #5c5a6e;
--color-tfa03-mut: oklch(0.48 0.025 275);
--color-tfa03-edge: #e3e1ee;
--color-tfa03-edge: oklch(0.91 0.012 275);
--color-tfa03-accedge: #9b8ce0;
--color-tfa03-accedge: oklch(0.72 0.1 285);
--color-tfa03-tint: #eeebfd;
--color-tfa03-tint: oklch(0.94 0.03 285);
--color-tfa03-acc: #5b3fd0;
--color-tfa03-acc: oklch(0.47 0.2 285);
--font-tfa03-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--font-tfa03-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tfa-03 {
width: 100%;
min-height: 100svh;
}
/* Same irreducible four lines as demo 02 — the animated panel, once, for the whole list. */
.tfa-03 [data-panel] {
interpolate-size: allow-keywords;
}
@supports (interpolate-size: allow-keywords) {
.tfa-03 details::details-content {
height: 0;
overflow: clip;
opacity: 0;
transition: height .38s cubic-bezier(.4,0,.2,1), opacity .3s, content-visibility .38s allow-discrete;
}
.tfa-03 details[open]::details-content {
height: auto;
opacity: 1;
}
}
@media (prefers-reduced-motion: reduce) {
.tfa-03 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.
.list:has([open]) .item:not([open]) summarybecomeshas-[details[open]]:[&>details:not([open])]:opacity-70on the list. Same three conditions, one class, declared on the element that owns the rule — and*:(direct children) is what makes it expressible without a custom selector.- The accent rail moved from
.item::beforeto a real<span aria-hidden>. Pseudo-elements are stylable in Tailwind but a per-statebefore:scale-y-*chain is longer and invisible in devtools; a 3px span costs one element and reads better. open:andgroup-open:cover every state style here, so the whole[open]attribute-selector family disappeared from the stylesheet. Only the::details-contentblock remains.- UI upgrade from the CSS original: muted copy went
oklch(0.52)→0.48and the accent0.55→0.47, clearing 4.5:1 on white where the original's dimmed-at-72% rows did not. Dimming itself is nowopacity-70on the whole item rather than on the summary, so the chevron dims with its row. - UI upgrade: the original relied on
:hover{opacity:1 !important}to undo its own dimming — a smell. Here the hover state changes ink colour instead, so no!importantand no fighting the cascade.
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 Exclusive Accordion — Only One FAQ Open at a Time
Source: https://codefronts.com/snippets/tailwind-css-faq-accordion/tailwind-exclusive-accordion-only-one-faq-open/
Only-one-open used to mean JavaScript closing siblings; now it is one HTML attribute. Give every <details> the same name and the browser enforces exclusivity like radio buttons. The port's contribution is the attention choreography: has-[details[open]]: on the list dims the closed questions, which is :has() written where you can see it.
## HTML
```html
<section class="tfa-03 w-full min-h-svh grid place-items-center bg-tfa03-bg font-tfa03-sans text-tfa03-ink px-5 py-12 bg-[linear-gradient(180deg,var(--color-tfa03-wash),var(--color-tfa03-bg)_42%)]">
<div class="w-[min(680px,100%)]">
<header>
<span class="inline-block rounded-full bg-tfa03-tint px-3 py-1.5 font-tfa03-mono text-[11.5px] font-semibold text-tfa03-acc">name="faq" · zero-JS exclusivity</span>
<h1 class="mt-4 text-[clamp(28px,5vw,40px)] font-extrabold leading-[1.08] tracking-[-0.025em]">Pricing questions, answered</h1>
<p class="mt-3 max-w-[54ch] text-[15px] leading-relaxed text-tfa03-mut">Open any question — the browser closes the previous one. One attribute, no JavaScript.</p>
</header>
<div data-panel class="mt-8 flex flex-col gap-2.5 has-[details[open]]:[&>details:not([open])]:opacity-70">
<details name="tfa03-faq" class="group relative overflow-hidden rounded-2xl border border-tfa03-edge bg-white transition-[border-color,box-shadow,opacity] duration-300 open:border-tfa03-accedge open:shadow-[0_14px_34px_-18px_oklch(0.45_0.14_275/0.35)]" open>
<span aria-hidden="true" class="absolute inset-y-0 left-0 w-[3px] origin-top scale-y-0 bg-tfa03-acc transition-transform duration-350 ease-[cubic-bezier(0.4,0,0.2,1)] group-open:scale-y-100 motion-reduce:transition-none"></span>
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3.5 px-5 py-4 text-[15.5px] font-semibold transition-colors duration-200 hover:text-tfa03-acc focus-visible:rounded-2xl focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa03-acc [&::-webkit-details-marker]:hidden">
<span class="font-tfa03-mono text-[11px] font-bold text-tfa03-acc">01</span>Is there a free plan?
<i aria-hidden="true" class="ml-auto size-2.5 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa03-mut transition-[rotate,translate,border-color] duration-350 group-hover:border-tfa03-acc group-open:translate-y-0.5 group-open:rotate-[225deg] group-open:border-tfa03-acc motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[58ch] pb-4 pl-12 pr-5 text-[14.5px] leading-[1.7] text-tfa03-mut">Yes — free forever for up to 3 projects and 2 seats, with no card required. It is a real plan, not a trial: teams ship production work on it every day.</p>
</details>
<details name="tfa03-faq" class="group relative overflow-hidden rounded-2xl border border-tfa03-edge bg-white transition-[border-color,box-shadow,opacity] duration-300 open:border-tfa03-accedge open:shadow-[0_14px_34px_-18px_oklch(0.45_0.14_275/0.35)]">
<span aria-hidden="true" class="absolute inset-y-0 left-0 w-[3px] origin-top scale-y-0 bg-tfa03-acc transition-transform duration-350 ease-[cubic-bezier(0.4,0,0.2,1)] group-open:scale-y-100 motion-reduce:transition-none"></span>
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3.5 px-5 py-4 text-[15.5px] font-semibold transition-colors duration-200 hover:text-tfa03-acc focus-visible:rounded-2xl focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa03-acc [&::-webkit-details-marker]:hidden">
<span class="font-tfa03-mono text-[11px] font-bold text-tfa03-acc">02</span>What counts as a “seat”?
<i aria-hidden="true" class="ml-auto size-2.5 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa03-mut transition-[rotate,translate,border-color] duration-350 group-hover:border-tfa03-acc group-open:translate-y-0.5 group-open:rotate-[225deg] group-open:border-tfa03-acc motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[58ch] pb-4 pl-12 pr-5 text-[14.5px] leading-[1.7] text-tfa03-mut">Anyone who can edit. Viewers and commenters are unlimited and free on every plan — you only pay for people who change things.</p>
</details>
<details name="tfa03-faq" class="group relative overflow-hidden rounded-2xl border border-tfa03-edge bg-white transition-[border-color,box-shadow,opacity] duration-300 open:border-tfa03-accedge open:shadow-[0_14px_34px_-18px_oklch(0.45_0.14_275/0.35)]">
<span aria-hidden="true" class="absolute inset-y-0 left-0 w-[3px] origin-top scale-y-0 bg-tfa03-acc transition-transform duration-350 ease-[cubic-bezier(0.4,0,0.2,1)] group-open:scale-y-100 motion-reduce:transition-none"></span>
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3.5 px-5 py-4 text-[15.5px] font-semibold transition-colors duration-200 hover:text-tfa03-acc focus-visible:rounded-2xl focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa03-acc [&::-webkit-details-marker]:hidden">
<span class="font-tfa03-mono text-[11px] font-bold text-tfa03-acc">03</span>Do prices include tax?
<i aria-hidden="true" class="ml-auto size-2.5 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa03-mut transition-[rotate,translate,border-color] duration-350 group-hover:border-tfa03-acc group-open:translate-y-0.5 group-open:rotate-[225deg] group-open:border-tfa03-acc motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[58ch] pb-4 pl-12 pr-5 text-[14.5px] leading-[1.7] text-tfa03-mut">Prices are shown pre-tax; VAT/GST is added at checkout based on your billing country. US customers see applicable state sales tax, and every invoice is compliant for expensing.</p>
</details>
<details name="tfa03-faq" class="group relative overflow-hidden rounded-2xl border border-tfa03-edge bg-white transition-[border-color,box-shadow,opacity] duration-300 open:border-tfa03-accedge open:shadow-[0_14px_34px_-18px_oklch(0.45_0.14_275/0.35)]">
<span aria-hidden="true" class="absolute inset-y-0 left-0 w-[3px] origin-top scale-y-0 bg-tfa03-acc transition-transform duration-350 ease-[cubic-bezier(0.4,0,0.2,1)] group-open:scale-y-100 motion-reduce:transition-none"></span>
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3.5 px-5 py-4 text-[15.5px] font-semibold transition-colors duration-200 hover:text-tfa03-acc focus-visible:rounded-2xl focus-visible:-outline-offset-2 focus-visible:outline-2 focus-visible:outline-tfa03-acc [&::-webkit-details-marker]:hidden">
<span class="font-tfa03-mono text-[11px] font-bold text-tfa03-acc">04</span>Can I pay by invoice?
<i aria-hidden="true" class="ml-auto size-2.5 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa03-mut transition-[rotate,translate,border-color] duration-350 group-hover:border-tfa03-acc group-open:translate-y-0.5 group-open:rotate-[225deg] group-open:border-tfa03-acc motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[58ch] pb-4 pl-12 pr-5 text-[14.5px] leading-[1.7] text-tfa03-mut">Annual plans over $2,000 can be paid by bank transfer with NET-30 terms. Contact sales and we will set up procurement, security review and a countersigned DPA if you need one.</p>
</details>
</div>
<p class="mt-6 text-[12.5px] text-tfa03-mut">Closed questions dim via <code class="rounded bg-tfa03-tint px-1.5 py-0.5 font-tfa03-mono text-[0.88em] text-tfa03-acc">has-[details[open]]:</code> — attention follows the open panel.</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tfa03-bg: #fafafd;
--color-tfa03-bg: oklch(0.98 0.005 270);
--color-tfa03-wash: #eeecfb;
--color-tfa03-wash: oklch(0.94 0.025 275);
--color-tfa03-ink: #1f1d2b;
--color-tfa03-ink: oklch(0.22 0.03 275);
--color-tfa03-mut: #5c5a6e;
--color-tfa03-mut: oklch(0.48 0.025 275);
--color-tfa03-edge: #e3e1ee;
--color-tfa03-edge: oklch(0.91 0.012 275);
--color-tfa03-accedge: #9b8ce0;
--color-tfa03-accedge: oklch(0.72 0.1 285);
--color-tfa03-tint: #eeebfd;
--color-tfa03-tint: oklch(0.94 0.03 285);
--color-tfa03-acc: #5b3fd0;
--color-tfa03-acc: oklch(0.47 0.2 285);
--font-tfa03-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--font-tfa03-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tfa-03 {
width: 100%;
min-height: 100svh;
}
/* Same irreducible four lines as demo 02 — the animated panel, once, for the whole list. */
.tfa-03 [data-panel] {
interpolate-size: allow-keywords;
}
@supports (interpolate-size: allow-keywords) {
.tfa-03 details::details-content {
height: 0;
overflow: clip;
opacity: 0;
transition: height .38s cubic-bezier(.4,0,.2,1), opacity .3s, content-visibility .38s allow-discrete;
}
.tfa-03 details[open]::details-content {
height: auto;
opacity: 1;
}
}
@media (prefers-reduced-motion: reduce) {
.tfa-03 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 Exclusive Accordion — Only One FAQ Open at a Time
Source: https://codefronts.com/snippets/tailwind-css-faq-accordion/tailwind-exclusive-accordion-only-one-faq-open/
Only-one-open used to mean JavaScript closing siblings; now it is one HTML attribute. Give every <details> the same name and the browser enforces exclusivity like radio buttons. The port's contribution is the attention choreography: has-[details[open]]: on the list dims the closed questions, which is :has() written where you can see it.
## HTML
```html
<section class="tfa-03 w-full min-h-svh grid place-items-center bg-tfa03-bg font-tfa03-sans text-tfa03-ink px-5 py-12 bg-[linear-gradient(180deg,var(--color-tfa03-wash),var(--color-tfa03-bg)_42%)]">
<div class="w-[min(680px,100%)]">
<header>
<span class="inline-block rounded-full bg-tfa03-tint px-3 py-1.5 font-tfa03-mono text-[11.5px] font-semibold text-tfa03-acc">name="faq" · zero-JS exclusivity</span>
<h1 class="mt-4 text-[clamp(28px,5vw,40px)] font-extrabold leading-[1.08] tracking-[-0.025em]">Pricing questions, answered</h1>
<p class="mt-3 max-w-[54ch] text-[15px] leading-relaxed text-tfa03-mut">Open any question — the browser closes the previous one. One attribute, no JavaScript.</p>
</header>
<div data-panel class="mt-8 flex flex-col gap-2.5 has-[details[open]]:[&>details:not([open])]:opacity-70">
<details name="tfa03-faq" class="group relative overflow-hidden rounded-2xl border border-tfa03-edge bg-white transition-[border-color,box-shadow,opacity] duration-300 open:border-tfa03-accedge open:shadow-[0_14px_34px_-18px_oklch(0.45_0.14_275/0.35)]" open>
<span aria-hidden="true" class="absolute inset-y-0 left-0 w-[3px] origin-top scale-y-0 bg-tfa03-acc transition-transform duration-350 ease-[cubic-bezier(0.4,0,0.2,1)] group-open:scale-y-100 motion-reduce:transition-none"></span>
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3.5 px-5 py-4 text-[15.5px] font-semibold transition-colors duration-200 hover:text-tfa03-acc focus-visible:rounded-2xl focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa03-acc [&::-webkit-details-marker]:hidden">
<span class="font-tfa03-mono text-[11px] font-bold text-tfa03-acc">01</span>Is there a free plan?
<i aria-hidden="true" class="ml-auto size-2.5 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa03-mut transition-[rotate,translate,border-color] duration-350 group-hover:border-tfa03-acc group-open:translate-y-0.5 group-open:rotate-[225deg] group-open:border-tfa03-acc motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[58ch] pb-4 pl-12 pr-5 text-[14.5px] leading-[1.7] text-tfa03-mut">Yes — free forever for up to 3 projects and 2 seats, with no card required. It is a real plan, not a trial: teams ship production work on it every day.</p>
</details>
<details name="tfa03-faq" class="group relative overflow-hidden rounded-2xl border border-tfa03-edge bg-white transition-[border-color,box-shadow,opacity] duration-300 open:border-tfa03-accedge open:shadow-[0_14px_34px_-18px_oklch(0.45_0.14_275/0.35)]">
<span aria-hidden="true" class="absolute inset-y-0 left-0 w-[3px] origin-top scale-y-0 bg-tfa03-acc transition-transform duration-350 ease-[cubic-bezier(0.4,0,0.2,1)] group-open:scale-y-100 motion-reduce:transition-none"></span>
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3.5 px-5 py-4 text-[15.5px] font-semibold transition-colors duration-200 hover:text-tfa03-acc focus-visible:rounded-2xl focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa03-acc [&::-webkit-details-marker]:hidden">
<span class="font-tfa03-mono text-[11px] font-bold text-tfa03-acc">02</span>What counts as a “seat”?
<i aria-hidden="true" class="ml-auto size-2.5 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa03-mut transition-[rotate,translate,border-color] duration-350 group-hover:border-tfa03-acc group-open:translate-y-0.5 group-open:rotate-[225deg] group-open:border-tfa03-acc motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[58ch] pb-4 pl-12 pr-5 text-[14.5px] leading-[1.7] text-tfa03-mut">Anyone who can edit. Viewers and commenters are unlimited and free on every plan — you only pay for people who change things.</p>
</details>
<details name="tfa03-faq" class="group relative overflow-hidden rounded-2xl border border-tfa03-edge bg-white transition-[border-color,box-shadow,opacity] duration-300 open:border-tfa03-accedge open:shadow-[0_14px_34px_-18px_oklch(0.45_0.14_275/0.35)]">
<span aria-hidden="true" class="absolute inset-y-0 left-0 w-[3px] origin-top scale-y-0 bg-tfa03-acc transition-transform duration-350 ease-[cubic-bezier(0.4,0,0.2,1)] group-open:scale-y-100 motion-reduce:transition-none"></span>
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3.5 px-5 py-4 text-[15.5px] font-semibold transition-colors duration-200 hover:text-tfa03-acc focus-visible:rounded-2xl focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa03-acc [&::-webkit-details-marker]:hidden">
<span class="font-tfa03-mono text-[11px] font-bold text-tfa03-acc">03</span>Do prices include tax?
<i aria-hidden="true" class="ml-auto size-2.5 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa03-mut transition-[rotate,translate,border-color] duration-350 group-hover:border-tfa03-acc group-open:translate-y-0.5 group-open:rotate-[225deg] group-open:border-tfa03-acc motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[58ch] pb-4 pl-12 pr-5 text-[14.5px] leading-[1.7] text-tfa03-mut">Prices are shown pre-tax; VAT/GST is added at checkout based on your billing country. US customers see applicable state sales tax, and every invoice is compliant for expensing.</p>
</details>
<details name="tfa03-faq" class="group relative overflow-hidden rounded-2xl border border-tfa03-edge bg-white transition-[border-color,box-shadow,opacity] duration-300 open:border-tfa03-accedge open:shadow-[0_14px_34px_-18px_oklch(0.45_0.14_275/0.35)]">
<span aria-hidden="true" class="absolute inset-y-0 left-0 w-[3px] origin-top scale-y-0 bg-tfa03-acc transition-transform duration-350 ease-[cubic-bezier(0.4,0,0.2,1)] group-open:scale-y-100 motion-reduce:transition-none"></span>
<summary class="flex min-h-11 cursor-pointer list-none items-center gap-3.5 px-5 py-4 text-[15.5px] font-semibold transition-colors duration-200 hover:text-tfa03-acc focus-visible:rounded-2xl focus-visible:-outline-offset-2 focus-visible:outline-2 focus-visible:outline-tfa03-acc [&::-webkit-details-marker]:hidden">
<span class="font-tfa03-mono text-[11px] font-bold text-tfa03-acc">04</span>Can I pay by invoice?
<i aria-hidden="true" class="ml-auto size-2.5 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa03-mut transition-[rotate,translate,border-color] duration-350 group-hover:border-tfa03-acc group-open:translate-y-0.5 group-open:rotate-[225deg] group-open:border-tfa03-acc motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[58ch] pb-4 pl-12 pr-5 text-[14.5px] leading-[1.7] text-tfa03-mut">Annual plans over $2,000 can be paid by bank transfer with NET-30 terms. Contact sales and we will set up procurement, security review and a countersigned DPA if you need one.</p>
</details>
</div>
<p class="mt-6 text-[12.5px] text-tfa03-mut">Closed questions dim via <code class="rounded bg-tfa03-tint px-1.5 py-0.5 font-tfa03-mono text-[0.88em] text-tfa03-acc">has-[details[open]]:</code> — attention follows the open panel.</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tfa03-bg: #fafafd;
--color-tfa03-bg: oklch(0.98 0.005 270);
--color-tfa03-wash: #eeecfb;
--color-tfa03-wash: oklch(0.94 0.025 275);
--color-tfa03-ink: #1f1d2b;
--color-tfa03-ink: oklch(0.22 0.03 275);
--color-tfa03-mut: #5c5a6e;
--color-tfa03-mut: oklch(0.48 0.025 275);
--color-tfa03-edge: #e3e1ee;
--color-tfa03-edge: oklch(0.91 0.012 275);
--color-tfa03-accedge: #9b8ce0;
--color-tfa03-accedge: oklch(0.72 0.1 285);
--color-tfa03-tint: #eeebfd;
--color-tfa03-tint: oklch(0.94 0.03 285);
--color-tfa03-acc: #5b3fd0;
--color-tfa03-acc: oklch(0.47 0.2 285);
--font-tfa03-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--font-tfa03-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tfa-03 {
width: 100%;
min-height: 100svh;
}
/* Same irreducible four lines as demo 02 — the animated panel, once, for the whole list. */
.tfa-03 [data-panel] {
interpolate-size: allow-keywords;
}
@supports (interpolate-size: allow-keywords) {
.tfa-03 details::details-content {
height: 0;
overflow: clip;
opacity: 0;
transition: height .38s cubic-bezier(.4,0,.2,1), opacity .3s, content-visibility .38s allow-discrete;
}
.tfa-03 details[open]::details-content {
height: auto;
opacity: 1;
}
}
@media (prefers-reduced-motion: reduce) {
.tfa-03 details::details-content {
transition-duration: 1ms;
}
}
```How this works
Exclusivity is an attribute. Same-name details behave like a radio group: at most one holds open, and the browser removes it from the previously-open element. No listeners, no state array — and because the platform does the closing, proper toggle events still fire if you want analytics.
<details name="tfa03-faq" class="group" open>…</details>
<details name="tfa03-faq" class="group">…</details>The dimming is the interesting port. The CSS version wrote .list:has([open]) .item:not([open]) summary{opacity:.72} — three selectors deep, far from the markup. v4 states it on the list as a variant stack:
class="has-[details[open]]:[&>details:not([open])]:opacity-70"Read it right to left: any direct child that is not open, when the list has an open details, dims. *: (the direct-children variant) is what makes this expressible at all — without it you would be writing a plain CSS rule.
The accent rail became a real element. Tailwind can style before:, but animating a pseudo-element's scale per-state reads badly in a class list; a 3px <span> with origin-top scale-y-0 group-open:scale-y-100 is shorter, inspectable in devtools, and identical on screen.
UX note before shipping: exclusive accordions read tidy but punish comparison. Use only-one-open when answers are long and independent (pricing objections, legal); use demo 04's multi-open when users cross-reference.
Make it yours
- Independent groups on one page: different
namevalues, e.g.name="billing"andname="security". - Start with one open: put
openon exactly one item — two are auto-resolved to the last. - Dimming strength:
opacity-70is gentle;opacity-60is directive,opacity-80nearly invisible. - Legacy target? Swap to demo 01's markup with
type="radio" name="faq"for identical UX in pre-2023 browsers.
Gotchas — read before shipping
- The
namemust be an identical string —faqandFaqare two groups. - Never set
openon two same-name details in source: browsers keep only the last, which can surprise a server-rendered diff. has-[details[open]]:needs the bracket form; there is no built-in shorthand for "has an open details descendant".- Deep-linking into a collapsed panel needs the
openattribute added server-side, or the fragment scrolls to a closed item.
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 120+.
details[name] exclusivity shipped across engines by late 2024. In older browsers the attribute is ignored and the FAQ degrades to multi-open — nothing breaks. :has() drives the dimming (Firefox 121); without it closed items simply stay at full opacity.