- No data uploaded
- Instant results
Tailwind CSS FAQ Accordion for Vanilla JS
A production-ready minimal faq accordion: a frequently-asked-questions section with four expandable items, each toggled by a button that exposes its state via aria-expanded. Pick your brand color, toggle dark mode and corner radius — the live preview and the Vanilla JS code update instantly in your browser.
Live component editor
<!-- Requires Tailwind CSS v3 (CLI/PostCSS build, or the Play CDN for prototypes) -->
<section class="px-6 py-16">
<div class="max-w-2xl mx-auto">
<h2 class="text-3xl font-bold text-center text-slate-900">Frequently asked questions</h2>
<div class="mt-10 flex flex-col gap-3">
<div class="bg-white border border-slate-200 shadow-sm rounded-xl">
<button type="button" class="w-full flex items-center justify-between gap-4 px-5 py-4 text-left font-semibold text-slate-900" data-toggle="q1" data-expanded="q1" aria-expanded="true" aria-controls="faq-a1">
<span>Can I cancel anytime?</span><span class="text-xl font-bold text-[#4f46e5]" aria-hidden="true">+</span>
</button>
<div id="faq-a1" data-show="q1">
<p class="px-5 pb-4 text-sm leading-relaxed text-slate-500">Yes. Cancel from your billing page and you keep access until the end of the period.</p>
</div>
</div>
<div class="bg-white border border-slate-200 shadow-sm rounded-xl">
<button type="button" class="w-full flex items-center justify-between gap-4 px-5 py-4 text-left font-semibold text-slate-900" data-toggle="q2" data-expanded="q2" aria-expanded="false" aria-controls="faq-a2">
<span>Do you offer a free trial?</span><span class="text-xl font-bold text-[#4f46e5]" aria-hidden="true">+</span>
</button>
<div id="faq-a2" data-show="q2" hidden>
<p class="px-5 pb-4 text-sm leading-relaxed text-slate-500">Every paid plan starts with a 14-day free trial — no credit card required.</p>
</div>
</div>
<div class="bg-white border border-slate-200 shadow-sm rounded-xl">
<button type="button" class="w-full flex items-center justify-between gap-4 px-5 py-4 text-left font-semibold text-slate-900" data-toggle="q3" data-expanded="q3" aria-expanded="false" aria-controls="faq-a3">
<span>Which payment methods do you accept?</span><span class="text-xl font-bold text-[#4f46e5]" aria-hidden="true">+</span>
</button>
<div id="faq-a3" data-show="q3" hidden>
<p class="px-5 pb-4 text-sm leading-relaxed text-slate-500">All major cards, UPI, netbanking and invoicing for annual plans.</p>
</div>
</div>
<div class="bg-white border border-slate-200 shadow-sm rounded-xl">
<button type="button" class="w-full flex items-center justify-between gap-4 px-5 py-4 text-left font-semibold text-slate-900" data-toggle="q4" data-expanded="q4" aria-expanded="false" aria-controls="faq-a4">
<span>Is my data secure?</span><span class="text-xl font-bold text-[#4f46e5]" aria-hidden="true">+</span>
</button>
<div id="faq-a4" data-show="q4" hidden>
<p class="px-5 pb-4 text-sm leading-relaxed text-slate-500">Data is encrypted in transit and at rest, and we never sell personal information.</p>
</div>
</div>
</div>
</div>
</section>
<script>
(() => {
const state = { q1: true, q2: false, q3: false, q4: false };
const actions = { };
const pair = (s) => s.split(':');
const sync = () => {
document.querySelectorAll('[data-show]').forEach((el) => (el.hidden = !state[el.dataset.show]));
document.querySelectorAll('[data-hide]').forEach((el) => (el.hidden = !!state[el.dataset.hide]));
document.querySelectorAll('[data-when]').forEach((el) => { const [k, v] = pair(el.dataset.when); el.hidden = state[k] !== v; });
document.querySelectorAll('[data-pressed]').forEach((el) => { const [k, v] = pair(el.dataset.pressed); el.setAttribute('aria-pressed', String(state[k] === v)); });
document.querySelectorAll('[data-expanded]').forEach((el) => el.setAttribute('aria-expanded', String(!!state[el.dataset.expanded])));
};
document.addEventListener('click', (e) => {
const t = e.target.closest('[data-toggle],[data-open],[data-close],[data-set],[data-call]');
if (!t) return;
const { toggle, open, close, set, call } = t.dataset;
if (call) actions[call]?.(e);
if (toggle) state[toggle] = !state[toggle];
if (open) state[open] = true;
if (close) state[close] = false;
if (set) { const [k, v] = pair(set); state[k] = v; }
sync();
});
sync();
})();
</script>
More Tailwind components for Vanilla JS
All components →- Pricing Table A three-tier pricing section with a monthly/yearly billing toggle, a highlighted “most popular” plan and feature checklists
- Contact Form A contact card with name, email, a topic selector, a message textarea and a submit button
- Feature Grid A marketing section with a centered heading and a responsive grid of six feature cards, each with an icon badge, title and description
- Currency Pricing Table A dynamic pricing section that detects the visitor’s currency, shows purchasing-power-adjusted regional prices and lets users switch between USD, EUR, GBP, INR and JPY
- Testimonial Slider A customer testimonial carousel that shows one quote at a time with labelled slide buttons — no autoplay, so users stay in control
- Login Modal A centered sign-in dialog with email and password fields, “remember me”, a forgot-password link and a social sign-in button
- Signup Form A registration card with name, email and password fields, a password hint, a terms-of-service checkbox and a primary call to action
- Navbar A responsive top navigation bar with a logo, primary links, a sign-in/CTA pair on desktop and a collapsible hamburger menu on mobile
Install Tailwind CSS for Vanilla JS
Prototype instantly with the Play CDN, or install the Tailwind CLI for production:
<script src="https://cdn.tailwindcss.com"></script>npm install -D tailwindcss@3
npx tailwindcss init
npx tailwindcss -i ./src/input.css -o ./dist/output.css --watchAdd ./**/*.html to content in tailwind.config.js and put the three @tailwind directives in src/input.css.
Use the faq accordion in Vanilla JS
Paste the markup where the component should appear. The small inline <script> wires up the interactive state with one delegated click listener — no framework needed.
Accessibility & customization
Each question is a <button> with aria-expanded and aria-controls pointing at its answer panel, so screen readers announce open/closed state and keyboard users can operate it with Enter or Space.
Every color, radius and dark-mode choice is baked into plain utility classes, so the copied code has no runtime dependency on this site.
Compatibility
| Item | Details |
|---|---|
| CSS framework | Tailwind CSS v3.4+ |
| Library | Plain HTML + optional vanilla JS |
| Interactive state | q1, q2, q3, q4 |
| Dark mode | Yes — toggle in the editor |
| Style | Minimal |