Introduction
Let’s build an Interactive FAQ Accordion for Astro. Modern web users expect interactive, accessible, and visually appealing content. One of the most effective ways to present frequently asked questions (FAQs) is with an accordion component—an interface element that allows users to expand and collapse answers as needed. In this article, we’ll walk through the entire process of adding a dynamic FAQ accordion to an Astro blog, from planning and implementation to troubleshooting and SEO optimization.
1. Planning the FAQ Feature
Before writing any code, it’s important to clarify your goals and requirements:
- User Experience: The accordion should be easy to use, accessible, and visually consistent with your site.
- Content Management: FAQ data should be easy to update, ideally stored in your markdown frontmatter.
- SEO: The FAQ should be marked up with structured data (FAQPage schema) for rich search results.
- Performance: The component should only load client-side JavaScript when needed.
2. Structuring FAQ Data in Markdown
Astro’s content collections allow you to store blog posts as markdown files with YAML frontmatter. To make your FAQ dynamic, add an array of question/answer objects to the frontmatter:
---
title: "How to Add an Accordion to Astro"
description: "A step-by-step guide to adding an interactive FAQ accordion to your Astro blog."
faq:
- title: "What is an accordion?"
content: "An accordion is a UI component that expands to reveal hidden content."
- title: "Why use an accordion for FAQs?"
content: "It keeps the page tidy and lets users focus on the questions they care about."
---
This approach keeps your content and logic separate, making it easy to update FAQs without touching code.
3. Creating the Accordion Component
Astro supports multiple frameworks for interactive components. For maximum compatibility and interactivity, we’ll use React. First, ensure you have the React integration:
npx astro add react
Then, create a new file src/components/Accordion.jsx
:
import React, { useState } from 'react';
import './Accordion.css';
export default function Accordion({ items = [] }) {
const [openIndex, setOpenIndex] = useState(-1);
const toggle = (index) => {
setOpenIndex(openIndex === index ? -1 : index);
};
return (
<div className="accordion">
{items.map((item, i) => (
<div className="accordion-item" key={i}>
<div className="accordion-header" onClick={() => toggle(i)}>
{item.title}
</div>
<div className={`accordion-panel${openIndex === i ? ' open' : ''}`}>
{item.content}
</div>
</div>
))}
</div>
);
}
4. Styling the Accordion
Create a CSS file src/components/Accordion.css
:
.accordion {
border-radius: 8px;
overflow: hidden;
border: 1px solid #ddd;
}
.accordion-item + .accordion-item {
border-top: 1px solid #ddd;
}
.accordion-header {
background: #f7f7f7;
cursor: pointer;
padding: 1em;
font-weight: bold;
transition: background 0.2s;
}
.accordion-header:hover {
background: #eaeaea;
}
.accordion-panel {
padding: 1em;
background: #fff;
display: none;
}
.accordion-panel.open {
display: block;
}
5. Passing FAQ Data to the Accordion
In your Astro blog post page (e.g., src/pages/blog/[...slug].astro
), import the Accordion and pass the FAQ data from the frontmatter:
---
import Accordion from '../../components/Accordion.jsx';
import '../../components/Accordion.css';
const { post } = Astro.props;
---
<main>
<h1>{post.data.title}</h1>
<article>
<Content />
{post.data.faq && <Accordion items={post.data.faq} client:load />}
</article>
</main>
The client:load
directive ensures the React component hydrates on the client, enabling interactivity.
6. Troubleshooting Common Issues
a. React Integration Not Found:
If you see an error like “No valid renderer was found for the .jsx
file extension,” make sure you’ve run npx astro add react
and that your astro.config.mjs
includes react()
in the integrations
array.
b. Dependency Conflicts:
If you get npm errors about React versions, ensure you’re using React 18 (not 19+) as of Astro v5. Example:
npm install react@18.2.0 react-dom@18.2.0
c. FAQ Not Showing:
Check that your content collection schema in src/content.config.ts
includes the faq
field:
faq: z.array(z.object({
title: z.string(),
content: z.string()
})).optional(),
d. Syntax Errors:
All JavaScript/TypeScript code in .astro
files must be inside the frontmatter block (between ---
lines).
7. Enhancing SEO with FAQ Schema
To help search engines understand your FAQ and potentially show rich results, add FAQPage structured data. In your BlogPostingJSONLD.astro
component, generate a FAQPage schema if FAQ data exists:
---
const { faq = [] } = Astro.props;
const faqSchema = faq.length > 0 ? {
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": faq.map(q => ({
"@type": "Question",
"name": q.title,
"acceptedAnswer": {
"@type": "Answer",
"text": q.content
}
}))
} : null;
---
{faqSchema && <script type="application/ld+json" set:html={JSON.stringify(faqSchema)} />}
This outputs valid JSON-LD for Google and other search engines.
8. Accessibility and Best Practices
- Use semantic HTML for headers and content.
- Ensure keyboard navigation works (e.g., allow Enter/Space to toggle).
- Add ARIA attributes for screen readers if needed.
9. Final Testing
-
Local Testing: Run
npm run dev
and verify the accordion works and FAQ data appears. - SEO Testing: Use Google’s Rich Results Test to validate your FAQPage schema.
- Cross-Browser: Check the accordion in multiple browsers and on mobile.
Conclusion
Adding an interactive FAQ accordion to your Astro blog is a powerful way to improve user experience and SEO. By storing FAQ data in markdown frontmatter, using a React component for interactivity, and outputting FAQPage schema, you ensure your content is both user-friendly and search-engine-optimized. With this approach, you can easily add, update, or remove FAQs as your content evolves—no code changes required.
If you follow these steps, you’ll have a robust, maintainable, and SEO-friendly FAQ section that delights your readers and helps your site stand out in search results.
Top comments (0)