19 / 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 Expand All and Collapse All FAQ Accordion Buttons
The bulk controls every long FAQ needs — Expand all / Collapse all over a native <details> list, for readers who skim, Ctrl+F or print. Fourteen lines of JS loop the open attribute; the interesting engineering is state truthfulness (each button disables when it would do nothing), and the print layer is now a print: variant instead of a media query.
Complete Tailwind CSS landing page templates in HTML, React, Next.js and Vue · from $49
Cruip · Affiliate link
The code
<section class="tfa-19 w-full min-h-svh grid place-items-center bg-tfa19-bg font-tfa19-sans text-tfa19-ink px-5 py-12">
<div class="w-[min(700px,100%)]">
<header class="flex flex-wrap items-end justify-between gap-4">
<div>
<h1 class="text-[clamp(24px,4.2vw,34px)] font-extrabold tracking-[-0.025em]">Rental agreement FAQ</h1>
<p class="mt-2 max-w-[44ch] text-[14px] leading-relaxed text-tfa19-mut">Bulk controls for readers who skim, search, or print. Buttons disable when they would do nothing.</p>
</div>
<div role="group" aria-label="Bulk expand controls" class="flex gap-2 print:hidden">
<button type="button" id="tfa19-expand" class="min-h-11 cursor-pointer rounded-[11px] border border-tfa19-accedge bg-white px-4 font-tfa19-sans text-[13.5px] font-bold text-tfa19-acc transition-[background-color,translate,opacity] duration-200 enabled:hover:bg-tfa19-tint enabled:hover:-translate-y-px focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tfa19-acc disabled:cursor-default disabled:opacity-50 motion-reduce:transition-colors">Expand all</button>
<button type="button" id="tfa19-collapse" disabled class="min-h-11 cursor-pointer rounded-[11px] border border-tfa19-accedge bg-white px-4 font-tfa19-sans text-[13.5px] font-bold text-tfa19-acc transition-[background-color,translate,opacity] duration-200 enabled:hover:bg-tfa19-tint enabled:hover:-translate-y-px focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tfa19-acc disabled:cursor-default disabled:opacity-50 motion-reduce:transition-colors">Collapse all</button>
</div>
</header>
<div data-panel id="tfa19-list" class="mt-6 flex flex-col gap-2.5">
<details class="group rounded-[13px] border border-tfa19-edge bg-white transition-[border-color,box-shadow] duration-300 open:border-tfa19-accedge open:shadow-[0_10px_26px_-18px_oklch(0.52_0.14_155/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center justify-between gap-4 px-4 py-3.5 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa19-acc focus-visible:rounded-[13px] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa19-acc [&::-webkit-details-marker]:hidden">How much is the security deposit?
<i aria-hidden="true" class="size-2 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa19-acc transition-[rotate,translate] duration-350 group-open:translate-y-0.5 group-open:rotate-[225deg] motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[60ch] px-4 pb-3.5 text-[13.5px] leading-[1.7] text-tfa19-mut">One month of rent, held in a government-approved deposit scheme within 14 days of payment — you receive the scheme certificate by email, and interest accrues to you, not us.</p>
</details>
<details class="group rounded-[13px] border border-tfa19-edge bg-white transition-[border-color,box-shadow] duration-300 open:border-tfa19-accedge open:shadow-[0_10px_26px_-18px_oklch(0.52_0.14_155/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center justify-between gap-4 px-4 py-3.5 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa19-acc focus-visible:rounded-[13px] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa19-acc [&::-webkit-details-marker]:hidden">Are pets allowed?
<i aria-hidden="true" class="size-2 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa19-acc transition-[rotate,translate] duration-350 group-open:translate-y-0.5 group-open:rotate-[225deg] motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[60ch] px-4 pb-3.5 text-[13.5px] leading-[1.7] text-tfa19-mut">Cats and dogs under 25kg, with a pet addendum and a refundable pet deposit of $300. Aquariums under 100L need no addendum; exotic animals are case-by-case.</p>
</details>
<details class="group rounded-[13px] border border-tfa19-edge bg-white transition-[border-color,box-shadow] duration-300 open:border-tfa19-accedge open:shadow-[0_10px_26px_-18px_oklch(0.52_0.14_155/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center justify-between gap-4 px-4 py-3.5 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa19-acc focus-visible:rounded-[13px] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa19-acc [&::-webkit-details-marker]:hidden">Who handles repairs?
<i aria-hidden="true" class="size-2 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa19-acc transition-[rotate,translate] duration-350 group-open:translate-y-0.5 group-open:rotate-[225deg] motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[60ch] px-4 pb-3.5 text-[13.5px] leading-[1.7] text-tfa19-mut">Report through the tenant portal — urgent issues (water, heat, locks) get a four-hour response window, everything else three business days. Repairs under $150 caused by normal wear are always on us.</p>
</details>
<details class="group rounded-[13px] border border-tfa19-edge bg-white transition-[border-color,box-shadow] duration-300 open:border-tfa19-accedge open:shadow-[0_10px_26px_-18px_oklch(0.52_0.14_155/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center justify-between gap-4 px-4 py-3.5 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa19-acc focus-visible:rounded-[13px] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa19-acc [&::-webkit-details-marker]:hidden">Can I sublet or list on a short-let site?
<i aria-hidden="true" class="size-2 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa19-acc transition-[rotate,translate] duration-350 group-open:translate-y-0.5 group-open:rotate-[225deg] motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[60ch] px-4 pb-3.5 text-[13.5px] leading-[1.7] text-tfa19-mut">Long-term subletting is allowed with written consent and a referenced subtenant. Short-term letting is not permitted — it breaches both the lease and most building insurance policies.</p>
</details>
<details class="group rounded-[13px] border border-tfa19-edge bg-white transition-[border-color,box-shadow] duration-300 open:border-tfa19-accedge open:shadow-[0_10px_26px_-18px_oklch(0.52_0.14_155/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center justify-between gap-4 px-4 py-3.5 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa19-acc focus-visible:rounded-[13px] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa19-acc [&::-webkit-details-marker]:hidden">How do I end the tenancy?
<i aria-hidden="true" class="size-2 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa19-acc transition-[rotate,translate] duration-350 group-open:translate-y-0.5 group-open:rotate-[225deg] motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[60ch] px-4 pb-3.5 text-[13.5px] leading-[1.7] text-tfa19-mut">Two months of written notice after the initial fixed term, served via the portal. The move-out checklist and cleaning standard are attached to the lease — deposits return within 10 days of a clear inspection.</p>
</details>
<details class="group rounded-[13px] border border-tfa19-edge bg-white transition-[border-color,box-shadow] duration-300 open:border-tfa19-accedge open:shadow-[0_10px_26px_-18px_oklch(0.52_0.14_155/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center justify-between gap-4 px-4 py-3.5 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa19-acc focus-visible:rounded-[13px] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa19-acc [&::-webkit-details-marker]:hidden">What happens if rent is late?
<i aria-hidden="true" class="size-2 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa19-acc transition-[rotate,translate] duration-350 group-open:translate-y-0.5 group-open:rotate-[225deg] motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[60ch] px-4 pb-3.5 text-[13.5px] leading-[1.7] text-tfa19-mut">A five-day grace period applies before any fee. After that it is a flat $50, never compounding — and if something has gone wrong, talk to us first; payment plans beat penalties for everyone.</p>
</details>
</div>
<p class="mt-5 text-[12.5px] text-tfa19-mut">Printing this page auto-expands every answer — <code class="rounded bg-tfa19-tint px-1.5 py-0.5 font-tfa19-mono text-[0.88em] text-tfa19-acc">print:hidden</code> on the controls plus three lines of print CSS.</p>
</div>
</section><section class="tfa-19 w-full min-h-svh grid place-items-center bg-tfa19-bg font-tfa19-sans text-tfa19-ink px-5 py-12">
<div class="w-[min(700px,100%)]">
<header class="flex flex-wrap items-end justify-between gap-4">
<div>
<h1 class="text-[clamp(24px,4.2vw,34px)] font-extrabold tracking-[-0.025em]">Rental agreement FAQ</h1>
<p class="mt-2 max-w-[44ch] text-[14px] leading-relaxed text-tfa19-mut">Bulk controls for readers who skim, search, or print. Buttons disable when they would do nothing.</p>
</div>
<div role="group" aria-label="Bulk expand controls" class="flex gap-2 print:hidden">
<button type="button" id="tfa19-expand" class="min-h-11 cursor-pointer rounded-[11px] border border-tfa19-accedge bg-white px-4 font-tfa19-sans text-[13.5px] font-bold text-tfa19-acc transition-[background-color,translate,opacity] duration-200 enabled:hover:bg-tfa19-tint enabled:hover:-translate-y-px focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tfa19-acc disabled:cursor-default disabled:opacity-50 motion-reduce:transition-colors">Expand all</button>
<button type="button" id="tfa19-collapse" disabled class="min-h-11 cursor-pointer rounded-[11px] border border-tfa19-accedge bg-white px-4 font-tfa19-sans text-[13.5px] font-bold text-tfa19-acc transition-[background-color,translate,opacity] duration-200 enabled:hover:bg-tfa19-tint enabled:hover:-translate-y-px focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tfa19-acc disabled:cursor-default disabled:opacity-50 motion-reduce:transition-colors">Collapse all</button>
</div>
</header>
<div data-panel id="tfa19-list" class="mt-6 flex flex-col gap-2.5">
<details class="group rounded-[13px] border border-tfa19-edge bg-white transition-[border-color,box-shadow] duration-300 open:border-tfa19-accedge open:shadow-[0_10px_26px_-18px_oklch(0.52_0.14_155/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center justify-between gap-4 px-4 py-3.5 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa19-acc focus-visible:rounded-[13px] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa19-acc [&::-webkit-details-marker]:hidden">How much is the security deposit?
<i aria-hidden="true" class="size-2 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa19-acc transition-[rotate,translate] duration-350 group-open:translate-y-0.5 group-open:rotate-[225deg] motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[60ch] px-4 pb-3.5 text-[13.5px] leading-[1.7] text-tfa19-mut">One month of rent, held in a government-approved deposit scheme within 14 days of payment — you receive the scheme certificate by email, and interest accrues to you, not us.</p>
</details>
<details class="group rounded-[13px] border border-tfa19-edge bg-white transition-[border-color,box-shadow] duration-300 open:border-tfa19-accedge open:shadow-[0_10px_26px_-18px_oklch(0.52_0.14_155/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center justify-between gap-4 px-4 py-3.5 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa19-acc focus-visible:rounded-[13px] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa19-acc [&::-webkit-details-marker]:hidden">Are pets allowed?
<i aria-hidden="true" class="size-2 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa19-acc transition-[rotate,translate] duration-350 group-open:translate-y-0.5 group-open:rotate-[225deg] motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[60ch] px-4 pb-3.5 text-[13.5px] leading-[1.7] text-tfa19-mut">Cats and dogs under 25kg, with a pet addendum and a refundable pet deposit of $300. Aquariums under 100L need no addendum; exotic animals are case-by-case.</p>
</details>
<details class="group rounded-[13px] border border-tfa19-edge bg-white transition-[border-color,box-shadow] duration-300 open:border-tfa19-accedge open:shadow-[0_10px_26px_-18px_oklch(0.52_0.14_155/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center justify-between gap-4 px-4 py-3.5 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa19-acc focus-visible:rounded-[13px] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa19-acc [&::-webkit-details-marker]:hidden">Who handles repairs?
<i aria-hidden="true" class="size-2 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa19-acc transition-[rotate,translate] duration-350 group-open:translate-y-0.5 group-open:rotate-[225deg] motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[60ch] px-4 pb-3.5 text-[13.5px] leading-[1.7] text-tfa19-mut">Report through the tenant portal — urgent issues (water, heat, locks) get a four-hour response window, everything else three business days. Repairs under $150 caused by normal wear are always on us.</p>
</details>
<details class="group rounded-[13px] border border-tfa19-edge bg-white transition-[border-color,box-shadow] duration-300 open:border-tfa19-accedge open:shadow-[0_10px_26px_-18px_oklch(0.52_0.14_155/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center justify-between gap-4 px-4 py-3.5 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa19-acc focus-visible:rounded-[13px] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa19-acc [&::-webkit-details-marker]:hidden">Can I sublet or list on a short-let site?
<i aria-hidden="true" class="size-2 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa19-acc transition-[rotate,translate] duration-350 group-open:translate-y-0.5 group-open:rotate-[225deg] motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[60ch] px-4 pb-3.5 text-[13.5px] leading-[1.7] text-tfa19-mut">Long-term subletting is allowed with written consent and a referenced subtenant. Short-term letting is not permitted — it breaches both the lease and most building insurance policies.</p>
</details>
<details class="group rounded-[13px] border border-tfa19-edge bg-white transition-[border-color,box-shadow] duration-300 open:border-tfa19-accedge open:shadow-[0_10px_26px_-18px_oklch(0.52_0.14_155/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center justify-between gap-4 px-4 py-3.5 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa19-acc focus-visible:rounded-[13px] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa19-acc [&::-webkit-details-marker]:hidden">How do I end the tenancy?
<i aria-hidden="true" class="size-2 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa19-acc transition-[rotate,translate] duration-350 group-open:translate-y-0.5 group-open:rotate-[225deg] motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[60ch] px-4 pb-3.5 text-[13.5px] leading-[1.7] text-tfa19-mut">Two months of written notice after the initial fixed term, served via the portal. The move-out checklist and cleaning standard are attached to the lease — deposits return within 10 days of a clear inspection.</p>
</details>
<details class="group rounded-[13px] border border-tfa19-edge bg-white transition-[border-color,box-shadow] duration-300 open:border-tfa19-accedge open:shadow-[0_10px_26px_-18px_oklch(0.52_0.14_155/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center justify-between gap-4 px-4 py-3.5 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa19-acc focus-visible:rounded-[13px] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa19-acc [&::-webkit-details-marker]:hidden">What happens if rent is late?
<i aria-hidden="true" class="size-2 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa19-acc transition-[rotate,translate] duration-350 group-open:translate-y-0.5 group-open:rotate-[225deg] motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[60ch] px-4 pb-3.5 text-[13.5px] leading-[1.7] text-tfa19-mut">A five-day grace period applies before any fee. After that it is a flat $50, never compounding — and if something has gone wrong, talk to us first; payment plans beat penalties for everyone.</p>
</details>
</div>
<p class="mt-5 text-[12.5px] text-tfa19-mut">Printing this page auto-expands every answer — <code class="rounded bg-tfa19-tint px-1.5 py-0.5 font-tfa19-mono text-[0.88em] text-tfa19-acc">print:hidden</code> on the controls plus three lines of print CSS.</p>
</div>
</section>@import "tailwindcss";
@theme {
--color-tfa19-bg: #f7faf7;
--color-tfa19-bg: oklch(0.975 0.008 145);
--color-tfa19-ink: #253028;
--color-tfa19-ink: oklch(0.24 0.03 155);
--color-tfa19-mut: #576159;
--color-tfa19-mut: oklch(0.46 0.025 150);
--color-tfa19-edge: #e0e8e1;
--color-tfa19-edge: oklch(0.91 0.015 148);
--color-tfa19-accedge: #7aab88;
--color-tfa19-accedge: oklch(0.7 0.08 155);
--color-tfa19-tint: #e6f2e9;
--color-tfa19-tint: oklch(0.94 0.03 155);
--color-tfa19-acc: #276b45;
--color-tfa19-acc: oklch(0.45 0.13 155);
--font-tfa19-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--font-tfa19-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tfa-19 {
width: 100%;
min-height: 100svh;
}
.tfa-19 [data-panel] {
interpolate-size: allow-keywords;
}
@supports (interpolate-size: allow-keywords) {
.tfa-19 details::details-content {
height: 0;
overflow: clip;
opacity: 0;
transition: height .35s cubic-bezier(.4,0,.2,1), opacity .3s, content-visibility .35s allow-discrete;
}
.tfa-19 details[open]::details-content {
height: auto;
opacity: 1;
}
}
/* The one thing print: variants cannot reach — a pseudo-element with a closed-state height. */
@media print {
.tfa-19 details::details-content {
display: block !important;
height: auto !important;
opacity: 1 !important;
overflow: visible !important;
}
}
@media (prefers-reduced-motion: reduce) {
.tfa-19 details::details-content {
transition-duration: 1ms;
}
}@import "tailwindcss";
@theme {
--color-tfa19-bg: #f7faf7;
--color-tfa19-bg: oklch(0.975 0.008 145);
--color-tfa19-ink: #253028;
--color-tfa19-ink: oklch(0.24 0.03 155);
--color-tfa19-mut: #576159;
--color-tfa19-mut: oklch(0.46 0.025 150);
--color-tfa19-edge: #e0e8e1;
--color-tfa19-edge: oklch(0.91 0.015 148);
--color-tfa19-accedge: #7aab88;
--color-tfa19-accedge: oklch(0.7 0.08 155);
--color-tfa19-tint: #e6f2e9;
--color-tfa19-tint: oklch(0.94 0.03 155);
--color-tfa19-acc: #276b45;
--color-tfa19-acc: oklch(0.45 0.13 155);
--font-tfa19-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--font-tfa19-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tfa-19 {
width: 100%;
min-height: 100svh;
}
.tfa-19 [data-panel] {
interpolate-size: allow-keywords;
}
@supports (interpolate-size: allow-keywords) {
.tfa-19 details::details-content {
height: 0;
overflow: clip;
opacity: 0;
transition: height .35s cubic-bezier(.4,0,.2,1), opacity .3s, content-visibility .35s allow-discrete;
}
.tfa-19 details[open]::details-content {
height: auto;
opacity: 1;
}
}
/* The one thing print: variants cannot reach — a pseudo-element with a closed-state height. */
@media print {
.tfa-19 details::details-content {
display: block !important;
height: auto !important;
opacity: 1 !important;
overflow: visible !important;
}
}
@media (prefers-reduced-motion: reduce) {
.tfa-19 details::details-content {
transition-duration: 1ms;
}
}(function(){
var root=document.querySelector('.tfa-19');if(!root||root.dataset.tfa19)return;root.dataset.tfa19='1';
var items=[].slice.call(root.querySelectorAll('#tfa19-list details')),
ex=root.querySelector('#tfa19-expand'),co=root.querySelector('#tfa19-collapse');
function sync(){
var open=items.filter(function(d){return d.open}).length;
ex.disabled=open===items.length;
co.disabled=open===0;
}
ex.addEventListener('click',function(){items.forEach(function(d){d.open=true})});
co.addEventListener('click',function(){items.forEach(function(d){d.open=false})});
items.forEach(function(d){d.addEventListener('toggle',sync)});
sync();
})();(function(){
var root=document.querySelector('.tfa-19');if(!root||root.dataset.tfa19)return;root.dataset.tfa19='1';
var items=[].slice.call(root.querySelectorAll('#tfa19-list details')),
ex=root.querySelector('#tfa19-expand'),co=root.querySelector('#tfa19-collapse');
function sync(){
var open=items.filter(function(d){return d.open}).length;
ex.disabled=open===items.length;
co.disabled=open===0;
}
ex.addEventListener('click',function(){items.forEach(function(d){d.open=true})});
co.addEventListener('click',function(){items.forEach(function(d){d.open=false})});
items.forEach(function(d){d.addEventListener('toggle',sync)});
sync();
})();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-tfa19-bg: #f7faf7;
--color-tfa19-bg: oklch(0.975 0.008 145);
--color-tfa19-ink: #253028;
--color-tfa19-ink: oklch(0.24 0.03 155);
--color-tfa19-mut: #576159;
--color-tfa19-mut: oklch(0.46 0.025 150);
--color-tfa19-edge: #e0e8e1;
--color-tfa19-edge: oklch(0.91 0.015 148);
--color-tfa19-accedge: #7aab88;
--color-tfa19-accedge: oklch(0.7 0.08 155);
--color-tfa19-tint: #e6f2e9;
--color-tfa19-tint: oklch(0.94 0.03 155);
--color-tfa19-acc: #276b45;
--color-tfa19-acc: oklch(0.45 0.13 155);
--font-tfa19-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--font-tfa19-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tfa-19 {
width: 100%;
min-height: 100svh;
}
.tfa-19 [data-panel] {
interpolate-size: allow-keywords;
}
@supports (interpolate-size: allow-keywords) {
.tfa-19 details::details-content {
height: 0;
overflow: clip;
opacity: 0;
transition: height .35s cubic-bezier(.4,0,.2,1), opacity .3s, content-visibility .35s allow-discrete;
}
.tfa-19 details[open]::details-content {
height: auto;
opacity: 1;
}
}
/* The one thing print: variants cannot reach — a pseudo-element with a closed-state height. */
@media print {
.tfa-19 details::details-content {
display: block !important;
height: auto !important;
opacity: 1 !important;
overflow: visible !important;
}
}
@media (prefers-reduced-motion: reduce) {
.tfa-19 details::details-content {
transition-duration: 1ms;
}
}@import "tailwindcss";
@theme {
--color-tfa19-bg: #f7faf7;
--color-tfa19-bg: oklch(0.975 0.008 145);
--color-tfa19-ink: #253028;
--color-tfa19-ink: oklch(0.24 0.03 155);
--color-tfa19-mut: #576159;
--color-tfa19-mut: oklch(0.46 0.025 150);
--color-tfa19-edge: #e0e8e1;
--color-tfa19-edge: oklch(0.91 0.015 148);
--color-tfa19-accedge: #7aab88;
--color-tfa19-accedge: oklch(0.7 0.08 155);
--color-tfa19-tint: #e6f2e9;
--color-tfa19-tint: oklch(0.94 0.03 155);
--color-tfa19-acc: #276b45;
--color-tfa19-acc: oklch(0.45 0.13 155);
--font-tfa19-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--font-tfa19-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tfa-19 {
width: 100%;
min-height: 100svh;
}
.tfa-19 [data-panel] {
interpolate-size: allow-keywords;
}
@supports (interpolate-size: allow-keywords) {
.tfa-19 details::details-content {
height: 0;
overflow: clip;
opacity: 0;
transition: height .35s cubic-bezier(.4,0,.2,1), opacity .3s, content-visibility .35s allow-discrete;
}
.tfa-19 details[open]::details-content {
height: auto;
opacity: 1;
}
}
/* The one thing print: variants cannot reach — a pseudo-element with a closed-state height. */
@media print {
.tfa-19 details::details-content {
display: block !important;
height: auto !important;
opacity: 1 !important;
overflow: visible !important;
}
}
@media (prefers-reduced-motion: reduce) {
.tfa-19 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&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&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
print:hiddenis the headline: a print-specific rule stated on the element it hides. The CSS version had a@media printblock at the bottom of the stylesheet that was easy to forget when the controls moved.enabled:hover:is a small but real upgrade over:hover:not(:disabled)— the same logic, read left to right, and impossible to get the precedence wrong.- Three lines of print CSS survive for
::details-content, which is the same irreducible pseudo-element as everywhere else in this collection. Utilities cover the controls; CSS covers the panel. - UI upgrade from the CSS original: the accent moved
oklch(0.52 0.14 155)→0.45 0.13, which matters because the button label is bold 13.5px green on white — the original sat at about 3.9:1. - UI upgrade: the disabled state is
opacity-50rather than0.45, keeping the label above 3:1 against the white button, and hover no longer lifts a disabled control — the original's:hover:not(:disabled)covered the background but not the translate.
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 Expand All and Collapse All FAQ Accordion Buttons
Source: https://codefronts.com/snippets/tailwind-css-faq-accordion/tailwind-expand-all-collapse-all-faq-accordion/
The bulk controls every long FAQ needs — Expand all / Collapse all over a native <details> list, for readers who skim, Ctrl+F or print. Fourteen lines of JS loop the open attribute; the interesting engineering is state truthfulness (each button disables when it would do nothing), and the print layer is now a print: variant instead of a media query.
## HTML
```html
<section class="tfa-19 w-full min-h-svh grid place-items-center bg-tfa19-bg font-tfa19-sans text-tfa19-ink px-5 py-12">
<div class="w-[min(700px,100%)]">
<header class="flex flex-wrap items-end justify-between gap-4">
<div>
<h1 class="text-[clamp(24px,4.2vw,34px)] font-extrabold tracking-[-0.025em]">Rental agreement FAQ</h1>
<p class="mt-2 max-w-[44ch] text-[14px] leading-relaxed text-tfa19-mut">Bulk controls for readers who skim, search, or print. Buttons disable when they would do nothing.</p>
</div>
<div role="group" aria-label="Bulk expand controls" class="flex gap-2 print:hidden">
<button type="button" id="tfa19-expand" class="min-h-11 cursor-pointer rounded-[11px] border border-tfa19-accedge bg-white px-4 font-tfa19-sans text-[13.5px] font-bold text-tfa19-acc transition-[background-color,translate,opacity] duration-200 enabled:hover:bg-tfa19-tint enabled:hover:-translate-y-px focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tfa19-acc disabled:cursor-default disabled:opacity-50 motion-reduce:transition-colors">Expand all</button>
<button type="button" id="tfa19-collapse" disabled class="min-h-11 cursor-pointer rounded-[11px] border border-tfa19-accedge bg-white px-4 font-tfa19-sans text-[13.5px] font-bold text-tfa19-acc transition-[background-color,translate,opacity] duration-200 enabled:hover:bg-tfa19-tint enabled:hover:-translate-y-px focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tfa19-acc disabled:cursor-default disabled:opacity-50 motion-reduce:transition-colors">Collapse all</button>
</div>
</header>
<div data-panel id="tfa19-list" class="mt-6 flex flex-col gap-2.5">
<details class="group rounded-[13px] border border-tfa19-edge bg-white transition-[border-color,box-shadow] duration-300 open:border-tfa19-accedge open:shadow-[0_10px_26px_-18px_oklch(0.52_0.14_155/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center justify-between gap-4 px-4 py-3.5 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa19-acc focus-visible:rounded-[13px] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa19-acc [&::-webkit-details-marker]:hidden">How much is the security deposit?
<i aria-hidden="true" class="size-2 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa19-acc transition-[rotate,translate] duration-350 group-open:translate-y-0.5 group-open:rotate-[225deg] motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[60ch] px-4 pb-3.5 text-[13.5px] leading-[1.7] text-tfa19-mut">One month of rent, held in a government-approved deposit scheme within 14 days of payment — you receive the scheme certificate by email, and interest accrues to you, not us.</p>
</details>
<details class="group rounded-[13px] border border-tfa19-edge bg-white transition-[border-color,box-shadow] duration-300 open:border-tfa19-accedge open:shadow-[0_10px_26px_-18px_oklch(0.52_0.14_155/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center justify-between gap-4 px-4 py-3.5 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa19-acc focus-visible:rounded-[13px] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa19-acc [&::-webkit-details-marker]:hidden">Are pets allowed?
<i aria-hidden="true" class="size-2 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa19-acc transition-[rotate,translate] duration-350 group-open:translate-y-0.5 group-open:rotate-[225deg] motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[60ch] px-4 pb-3.5 text-[13.5px] leading-[1.7] text-tfa19-mut">Cats and dogs under 25kg, with a pet addendum and a refundable pet deposit of $300. Aquariums under 100L need no addendum; exotic animals are case-by-case.</p>
</details>
<details class="group rounded-[13px] border border-tfa19-edge bg-white transition-[border-color,box-shadow] duration-300 open:border-tfa19-accedge open:shadow-[0_10px_26px_-18px_oklch(0.52_0.14_155/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center justify-between gap-4 px-4 py-3.5 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa19-acc focus-visible:rounded-[13px] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa19-acc [&::-webkit-details-marker]:hidden">Who handles repairs?
<i aria-hidden="true" class="size-2 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa19-acc transition-[rotate,translate] duration-350 group-open:translate-y-0.5 group-open:rotate-[225deg] motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[60ch] px-4 pb-3.5 text-[13.5px] leading-[1.7] text-tfa19-mut">Report through the tenant portal — urgent issues (water, heat, locks) get a four-hour response window, everything else three business days. Repairs under $150 caused by normal wear are always on us.</p>
</details>
<details class="group rounded-[13px] border border-tfa19-edge bg-white transition-[border-color,box-shadow] duration-300 open:border-tfa19-accedge open:shadow-[0_10px_26px_-18px_oklch(0.52_0.14_155/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center justify-between gap-4 px-4 py-3.5 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa19-acc focus-visible:rounded-[13px] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa19-acc [&::-webkit-details-marker]:hidden">Can I sublet or list on a short-let site?
<i aria-hidden="true" class="size-2 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa19-acc transition-[rotate,translate] duration-350 group-open:translate-y-0.5 group-open:rotate-[225deg] motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[60ch] px-4 pb-3.5 text-[13.5px] leading-[1.7] text-tfa19-mut">Long-term subletting is allowed with written consent and a referenced subtenant. Short-term letting is not permitted — it breaches both the lease and most building insurance policies.</p>
</details>
<details class="group rounded-[13px] border border-tfa19-edge bg-white transition-[border-color,box-shadow] duration-300 open:border-tfa19-accedge open:shadow-[0_10px_26px_-18px_oklch(0.52_0.14_155/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center justify-between gap-4 px-4 py-3.5 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa19-acc focus-visible:rounded-[13px] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa19-acc [&::-webkit-details-marker]:hidden">How do I end the tenancy?
<i aria-hidden="true" class="size-2 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa19-acc transition-[rotate,translate] duration-350 group-open:translate-y-0.5 group-open:rotate-[225deg] motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[60ch] px-4 pb-3.5 text-[13.5px] leading-[1.7] text-tfa19-mut">Two months of written notice after the initial fixed term, served via the portal. The move-out checklist and cleaning standard are attached to the lease — deposits return within 10 days of a clear inspection.</p>
</details>
<details class="group rounded-[13px] border border-tfa19-edge bg-white transition-[border-color,box-shadow] duration-300 open:border-tfa19-accedge open:shadow-[0_10px_26px_-18px_oklch(0.52_0.14_155/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center justify-between gap-4 px-4 py-3.5 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa19-acc focus-visible:rounded-[13px] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa19-acc [&::-webkit-details-marker]:hidden">What happens if rent is late?
<i aria-hidden="true" class="size-2 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa19-acc transition-[rotate,translate] duration-350 group-open:translate-y-0.5 group-open:rotate-[225deg] motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[60ch] px-4 pb-3.5 text-[13.5px] leading-[1.7] text-tfa19-mut">A five-day grace period applies before any fee. After that it is a flat $50, never compounding — and if something has gone wrong, talk to us first; payment plans beat penalties for everyone.</p>
</details>
</div>
<p class="mt-5 text-[12.5px] text-tfa19-mut">Printing this page auto-expands every answer — <code class="rounded bg-tfa19-tint px-1.5 py-0.5 font-tfa19-mono text-[0.88em] text-tfa19-acc">print:hidden</code> on the controls plus three lines of print CSS.</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tfa19-bg: #f7faf7;
--color-tfa19-bg: oklch(0.975 0.008 145);
--color-tfa19-ink: #253028;
--color-tfa19-ink: oklch(0.24 0.03 155);
--color-tfa19-mut: #576159;
--color-tfa19-mut: oklch(0.46 0.025 150);
--color-tfa19-edge: #e0e8e1;
--color-tfa19-edge: oklch(0.91 0.015 148);
--color-tfa19-accedge: #7aab88;
--color-tfa19-accedge: oklch(0.7 0.08 155);
--color-tfa19-tint: #e6f2e9;
--color-tfa19-tint: oklch(0.94 0.03 155);
--color-tfa19-acc: #276b45;
--color-tfa19-acc: oklch(0.45 0.13 155);
--font-tfa19-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--font-tfa19-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tfa-19 {
width: 100%;
min-height: 100svh;
}
.tfa-19 [data-panel] {
interpolate-size: allow-keywords;
}
@supports (interpolate-size: allow-keywords) {
.tfa-19 details::details-content {
height: 0;
overflow: clip;
opacity: 0;
transition: height .35s cubic-bezier(.4,0,.2,1), opacity .3s, content-visibility .35s allow-discrete;
}
.tfa-19 details[open]::details-content {
height: auto;
opacity: 1;
}
}
/* The one thing print: variants cannot reach — a pseudo-element with a closed-state height. */
@media print {
.tfa-19 details::details-content {
display: block !important;
height: auto !important;
opacity: 1 !important;
overflow: visible !important;
}
}
@media (prefers-reduced-motion: reduce) {
.tfa-19 details::details-content {
transition-duration: 1ms;
}
}
```
## JavaScript
```js
(function(){
var root=document.querySelector('.tfa-19');if(!root||root.dataset.tfa19)return;root.dataset.tfa19='1';
var items=[].slice.call(root.querySelectorAll('#tfa19-list details')),
ex=root.querySelector('#tfa19-expand'),co=root.querySelector('#tfa19-collapse');
function sync(){
var open=items.filter(function(d){return d.open}).length;
ex.disabled=open===items.length;
co.disabled=open===0;
}
ex.addEventListener('click',function(){items.forEach(function(d){d.open=true})});
co.addEventListener('click',function(){items.forEach(function(d){d.open=false})});
items.forEach(function(d){d.addEventListener('toggle',sync)});
sync();
})();
```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 Expand All and Collapse All FAQ Accordion Buttons
Source: https://codefronts.com/snippets/tailwind-css-faq-accordion/tailwind-expand-all-collapse-all-faq-accordion/
The bulk controls every long FAQ needs — Expand all / Collapse all over a native <details> list, for readers who skim, Ctrl+F or print. Fourteen lines of JS loop the open attribute; the interesting engineering is state truthfulness (each button disables when it would do nothing), and the print layer is now a print: variant instead of a media query.
## HTML
```html
<section class="tfa-19 w-full min-h-svh grid place-items-center bg-tfa19-bg font-tfa19-sans text-tfa19-ink px-5 py-12">
<div class="w-[min(700px,100%)]">
<header class="flex flex-wrap items-end justify-between gap-4">
<div>
<h1 class="text-[clamp(24px,4.2vw,34px)] font-extrabold tracking-[-0.025em]">Rental agreement FAQ</h1>
<p class="mt-2 max-w-[44ch] text-[14px] leading-relaxed text-tfa19-mut">Bulk controls for readers who skim, search, or print. Buttons disable when they would do nothing.</p>
</div>
<div role="group" aria-label="Bulk expand controls" class="flex gap-2 print:hidden">
<button type="button" id="tfa19-expand" class="min-h-11 cursor-pointer rounded-[11px] border border-tfa19-accedge bg-white px-4 font-tfa19-sans text-[13.5px] font-bold text-tfa19-acc transition-[background-color,translate,opacity] duration-200 enabled:hover:bg-tfa19-tint enabled:hover:-translate-y-px focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tfa19-acc disabled:cursor-default disabled:opacity-50 motion-reduce:transition-colors">Expand all</button>
<button type="button" id="tfa19-collapse" disabled class="min-h-11 cursor-pointer rounded-[11px] border border-tfa19-accedge bg-white px-4 font-tfa19-sans text-[13.5px] font-bold text-tfa19-acc transition-[background-color,translate,opacity] duration-200 enabled:hover:bg-tfa19-tint enabled:hover:-translate-y-px focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tfa19-acc disabled:cursor-default disabled:opacity-50 motion-reduce:transition-colors">Collapse all</button>
</div>
</header>
<div data-panel id="tfa19-list" class="mt-6 flex flex-col gap-2.5">
<details class="group rounded-[13px] border border-tfa19-edge bg-white transition-[border-color,box-shadow] duration-300 open:border-tfa19-accedge open:shadow-[0_10px_26px_-18px_oklch(0.52_0.14_155/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center justify-between gap-4 px-4 py-3.5 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa19-acc focus-visible:rounded-[13px] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa19-acc [&::-webkit-details-marker]:hidden">How much is the security deposit?
<i aria-hidden="true" class="size-2 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa19-acc transition-[rotate,translate] duration-350 group-open:translate-y-0.5 group-open:rotate-[225deg] motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[60ch] px-4 pb-3.5 text-[13.5px] leading-[1.7] text-tfa19-mut">One month of rent, held in a government-approved deposit scheme within 14 days of payment — you receive the scheme certificate by email, and interest accrues to you, not us.</p>
</details>
<details class="group rounded-[13px] border border-tfa19-edge bg-white transition-[border-color,box-shadow] duration-300 open:border-tfa19-accedge open:shadow-[0_10px_26px_-18px_oklch(0.52_0.14_155/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center justify-between gap-4 px-4 py-3.5 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa19-acc focus-visible:rounded-[13px] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa19-acc [&::-webkit-details-marker]:hidden">Are pets allowed?
<i aria-hidden="true" class="size-2 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa19-acc transition-[rotate,translate] duration-350 group-open:translate-y-0.5 group-open:rotate-[225deg] motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[60ch] px-4 pb-3.5 text-[13.5px] leading-[1.7] text-tfa19-mut">Cats and dogs under 25kg, with a pet addendum and a refundable pet deposit of $300. Aquariums under 100L need no addendum; exotic animals are case-by-case.</p>
</details>
<details class="group rounded-[13px] border border-tfa19-edge bg-white transition-[border-color,box-shadow] duration-300 open:border-tfa19-accedge open:shadow-[0_10px_26px_-18px_oklch(0.52_0.14_155/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center justify-between gap-4 px-4 py-3.5 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa19-acc focus-visible:rounded-[13px] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa19-acc [&::-webkit-details-marker]:hidden">Who handles repairs?
<i aria-hidden="true" class="size-2 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa19-acc transition-[rotate,translate] duration-350 group-open:translate-y-0.5 group-open:rotate-[225deg] motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[60ch] px-4 pb-3.5 text-[13.5px] leading-[1.7] text-tfa19-mut">Report through the tenant portal — urgent issues (water, heat, locks) get a four-hour response window, everything else three business days. Repairs under $150 caused by normal wear are always on us.</p>
</details>
<details class="group rounded-[13px] border border-tfa19-edge bg-white transition-[border-color,box-shadow] duration-300 open:border-tfa19-accedge open:shadow-[0_10px_26px_-18px_oklch(0.52_0.14_155/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center justify-between gap-4 px-4 py-3.5 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa19-acc focus-visible:rounded-[13px] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa19-acc [&::-webkit-details-marker]:hidden">Can I sublet or list on a short-let site?
<i aria-hidden="true" class="size-2 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa19-acc transition-[rotate,translate] duration-350 group-open:translate-y-0.5 group-open:rotate-[225deg] motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[60ch] px-4 pb-3.5 text-[13.5px] leading-[1.7] text-tfa19-mut">Long-term subletting is allowed with written consent and a referenced subtenant. Short-term letting is not permitted — it breaches both the lease and most building insurance policies.</p>
</details>
<details class="group rounded-[13px] border border-tfa19-edge bg-white transition-[border-color,box-shadow] duration-300 open:border-tfa19-accedge open:shadow-[0_10px_26px_-18px_oklch(0.52_0.14_155/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center justify-between gap-4 px-4 py-3.5 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa19-acc focus-visible:rounded-[13px] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa19-acc [&::-webkit-details-marker]:hidden">How do I end the tenancy?
<i aria-hidden="true" class="size-2 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa19-acc transition-[rotate,translate] duration-350 group-open:translate-y-0.5 group-open:rotate-[225deg] motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[60ch] px-4 pb-3.5 text-[13.5px] leading-[1.7] text-tfa19-mut">Two months of written notice after the initial fixed term, served via the portal. The move-out checklist and cleaning standard are attached to the lease — deposits return within 10 days of a clear inspection.</p>
</details>
<details class="group rounded-[13px] border border-tfa19-edge bg-white transition-[border-color,box-shadow] duration-300 open:border-tfa19-accedge open:shadow-[0_10px_26px_-18px_oklch(0.52_0.14_155/0.4)]">
<summary class="flex min-h-11 cursor-pointer list-none items-center justify-between gap-4 px-4 py-3.5 text-[15px] font-semibold transition-colors duration-200 hover:text-tfa19-acc focus-visible:rounded-[13px] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-tfa19-acc [&::-webkit-details-marker]:hidden">What happens if rent is late?
<i aria-hidden="true" class="size-2 shrink-0 -translate-y-0.5 rotate-45 border-b-2 border-r-2 border-tfa19-acc transition-[rotate,translate] duration-350 group-open:translate-y-0.5 group-open:rotate-[225deg] motion-reduce:transition-none"></i>
</summary>
<p class="max-w-[60ch] px-4 pb-3.5 text-[13.5px] leading-[1.7] text-tfa19-mut">A five-day grace period applies before any fee. After that it is a flat $50, never compounding — and if something has gone wrong, talk to us first; payment plans beat penalties for everyone.</p>
</details>
</div>
<p class="mt-5 text-[12.5px] text-tfa19-mut">Printing this page auto-expands every answer — <code class="rounded bg-tfa19-tint px-1.5 py-0.5 font-tfa19-mono text-[0.88em] text-tfa19-acc">print:hidden</code> on the controls plus three lines of print CSS.</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tfa19-bg: #f7faf7;
--color-tfa19-bg: oklch(0.975 0.008 145);
--color-tfa19-ink: #253028;
--color-tfa19-ink: oklch(0.24 0.03 155);
--color-tfa19-mut: #576159;
--color-tfa19-mut: oklch(0.46 0.025 150);
--color-tfa19-edge: #e0e8e1;
--color-tfa19-edge: oklch(0.91 0.015 148);
--color-tfa19-accedge: #7aab88;
--color-tfa19-accedge: oklch(0.7 0.08 155);
--color-tfa19-tint: #e6f2e9;
--color-tfa19-tint: oklch(0.94 0.03 155);
--color-tfa19-acc: #276b45;
--color-tfa19-acc: oklch(0.45 0.13 155);
--font-tfa19-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--font-tfa19-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tfa-19 {
width: 100%;
min-height: 100svh;
}
.tfa-19 [data-panel] {
interpolate-size: allow-keywords;
}
@supports (interpolate-size: allow-keywords) {
.tfa-19 details::details-content {
height: 0;
overflow: clip;
opacity: 0;
transition: height .35s cubic-bezier(.4,0,.2,1), opacity .3s, content-visibility .35s allow-discrete;
}
.tfa-19 details[open]::details-content {
height: auto;
opacity: 1;
}
}
/* The one thing print: variants cannot reach — a pseudo-element with a closed-state height. */
@media print {
.tfa-19 details::details-content {
display: block !important;
height: auto !important;
opacity: 1 !important;
overflow: visible !important;
}
}
@media (prefers-reduced-motion: reduce) {
.tfa-19 details::details-content {
transition-duration: 1ms;
}
}
```
## JavaScript
```js
(function(){
var root=document.querySelector('.tfa-19');if(!root||root.dataset.tfa19)return;root.dataset.tfa19='1';
var items=[].slice.call(root.querySelectorAll('#tfa19-list details')),
ex=root.querySelector('#tfa19-expand'),co=root.querySelector('#tfa19-collapse');
function sync(){
var open=items.filter(function(d){return d.open}).length;
ex.disabled=open===items.length;
co.disabled=open===0;
}
ex.addEventListener('click',function(){items.forEach(function(d){d.open=true})});
co.addEventListener('click',function(){items.forEach(function(d){d.open=false})});
items.forEach(function(d){d.addEventListener('toggle',sync)});
sync();
})();
```How this works
The mechanism is almost embarrassing. The open attribute is scriptable, so bulk control is a loop over d.open = true or false. What separates a good implementation is state truthfulness: after any change, recount and disable the useless button. A disabled Expand all tells users at a glance that everything is already open, where two live buttons imply hidden panels exist somewhere.
Listening to toggle, not to clicks, means the count stays right whether the change came from a button or from a user opening one question by hand. It is also the single place to hang analytics.
Printing is where the port pays off. Readers who print a FAQ want the answers, not a page of collapsed questions. The CSS version needed a @media print block with !important to beat the closed-state height; the utility version states print:hidden on the controls right next to them, and keeps three lines of print CSS for the one thing utilities cannot reach — ::details-content.
Make it yours
- Single-toggle variant: one button whose label flips, with
aria-pressedso AT announces the mode. Saves space, but the label changes under the cursor. - Remember state: serialise the open flags to localStorage on
toggleand restore on load — good for long legal FAQs. - Bulk animation: past about twenty items, zero the transition duration during a bulk op so twenty panels do not animate at once.
- Analytics: the
togglehandler already sees every open and close, however triggered.
Gotchas — read before shipping
- Setting
openin a loop fires onetoggleevent per item — keep the handler cheap, or checkevent.targetif you log. - Disabled buttons must keep readable contrast:
opacity-50here stays above 3:1 on the panel. Greyed-to-invisible controls fail WCAG 1.4.3. - The print rule for
::details-contentneeds!importantto beat the closed-state height inside the@supportsblock. - Do not remove the disabled state to look tidier — it is the only thing telling users the list is fully open.
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+.
details.open scripting and the toggle event are ancient, as is print CSS. The floor is Tailwind v4's generated sheet.