FAQ
Accordion-style FAQ section with toggle behavior for questions and answers.
Overview
The FAQ component renders a list of frequently asked questions as an accordion. Only one answer is visible at a time. Clicking a question toggles its answer and closes any previously open item.
File: src/components/FAQ.tsx
Data Structure
Questions are defined in the faqs array:
const faqs = [
{
question: "What's included?",
answer: "You get the complete source code for a production-ready SaaS boilerplate..."
},
// ...more entries
];Each entry has a question (string) and answer (string).
Toggle Behavior
The component uses a single openIndex state (type number | null):
const [openIndex, setOpenIndex] = useState<number | null>(null);
const toggle = (i: number) => {
setOpenIndex(openIndex === i ? null : i);
};- Clicking an open item sets
openIndextonull(closes it). - Clicking a closed item sets
openIndexto that item's index. - Only one item can be open at a time.
To allow multiple items open simultaneously, change openIndex to a Set<number> and toggle membership instead.
Customization
Add or edit questions
Add entries to the faqs array. There is no hard limit, but 5-8 questions is typical for a landing page.
{
question: "Do you offer refunds?",
answer: "Yes, we have a 30-day money-back guarantee."
},Change the section heading
<h2 className="text-center text-3xl font-bold text-gray-900 sm:text-4xl">
Common questions
</h2>Style the accordion items
Each FAQ item uses these key classes:
| Class | Purpose |
|---|---|
rounded-xl border border-gray-200 bg-white | Card-like item container |
px-6 py-5 | Padding for the clickable button |
rotate-180 | Rotates the chevron when item is open |
bg-gray-50 | Section background for contrast |
Chevron animation
The ChevronDown icon rotates 180 degrees when an item is open, using transition-transform for a smooth animation.
Tips
- Keep answers concise (1-3 sentences). Link to documentation for detailed explanations.
- Order questions by frequency: put the most common questions first.
- Use rich text in answers by replacing the
<p>with JSX containing<a>tags or<strong>elements. - The section uses
bg-gray-50to visually separate it from adjacent white sections.
Done reading? Mark this page as complete.