MDX Notes
Build an Accordion component for MDX — animated expand/collapse, grouped panels, FAQ patterns, and proper ARIA support.
Accordions let you hide content behind clickable headers. Readers scan the titles, expand what they care about, and skip the rest. They're perfect for FAQs, API references, long code examples — anything where showing everything at once would overwhelm the page.
Why Accordions in MDX?
Long docs pages scare people off. Accordions give readers a way to scan quickly and drill into just the parts they need. All the info stays on one page, but it doesn't hit them in the face all at once.
Component Source Code
Here's the full Accordion system with smooth height animations:
Basic Usage in MDX
Drop in a single standalone accordion like this:
import { Accordion } from '../components/Accordion';
# Getting Started
<Accordion title="System Requirements" defaultOpen>
- Node.js 18 or later
- npm 8+ or yarn 1.22+
- A code editor (VS Code recommended)
- Git for version control
</Accordion>
<Accordion title="Optional Dependencies">
These packages are optional but enhance your experience:
- `prettier` — for code formatting
- `eslint` — for code linting
- `husky` — for git hooks
</Accordion>Accordion Group (Single Open)
Want only one accordion open at a time? Wrap them in an AccordionGroup. When you click one, the others close:
import { Accordion, AccordionGroup } from '../components/Accordion';
# API Reference
<AccordionGroup>
<Accordion id="get-users" title="GET /api/users">
Retrieves a list of all users in the system.
**Parameters:**
- `limit` (optional) — Maximum results to return
- `offset` (optional) — Pagination offset
**Response:** `200 OK` with JSON array of user objects.
</Accordion>
<Accordion id="post-users" title="POST /api/users">
Creates a new user in the system.
**Body:**{ "name": "John Doe", "email": "john@example.com" }
**Response:** `201 Created` with the new user object.
</Accordion>
<Accordion id="delete-users" title="DELETE /api/users/:id">
Permanently removes a user from the system.
**Parameters:**
- `id` (required) — The user's unique identifier
**Response:** `204 No Content`
</Accordion>
</AccordionGroup>Allow Multiple Open
If you want users to expand several panels at once, pass allowMultiple:
<AccordionGroup allowMultiple>
<Accordion id="section-1" title="Section One">
This section can be open simultaneously with others.
</Accordion>
<Accordion id="section-2" title="Section Two">
Multiple sections can be expanded at the same time.
</Accordion>
<Accordion id="section-3" title="Section Three">
The allowMultiple prop enables this behavior.
</Accordion>
</AccordionGroup>Initially Open State
Need something visible right away? Use defaultOpen:
<Accordion title="Important: Read First" defaultOpen>
This accordion starts in the expanded state so readers
see the content immediately. Useful for critical
information or introductory notes.
</Accordion>FAQ Pattern
Accordions are a natural fit for FAQ pages:
import { Accordion, AccordionGroup } from '../components/Accordion';
# Frequently Asked Questions
<AccordionGroup>
<Accordion id="faq-1" title="What is MDX?">
MDX is a format that lets you write JSX directly in your
Markdown documents. You can import components, use them inline
with your text content, and even export data from your MDX files.
</Accordion>
<Accordion id="faq-2" title="Is MDX compatible with existing Markdown?">
Yes! MDX is a superset of Markdown. All valid Markdown is also
valid MDX. You can gradually adopt components without rewriting
existing content.
</Accordion>
<Accordion id="faq-3" title="What frameworks support MDX?">
MDX works with Next.js, Gatsby, Remix, Astro, Docusaurus,
and many other React-based frameworks. There's also support
for Vue and Svelte through community plugins.
</Accordion>
<Accordion id="faq-4" title="How do I style MDX components?">
You can use CSS Modules, Tailwind CSS, styled-components,
Emotion, or any other CSS-in-JS solution. The components
are just React components, so any styling approach works.
</Accordion>
</AccordionGroup>Nested Accordions
You can nest them for hierarchical content:
<Accordion title="Frontend Technologies">
<AccordionGroup>
<Accordion id="react" title="React" icon="⚛️">
A JavaScript library for building user interfaces.
React uses a component-based architecture and virtual DOM.
</Accordion>
<Accordion id="vue" title="Vue.js" icon="💚">
A progressive framework for building user interfaces.
Vue is designed to be incrementally adoptable.
</Accordion>
<Accordion id="svelte" title="Svelte" icon="🔥">
A compiler that converts components into efficient
imperative code that directly manipulates the DOM.
</Accordion>
</AccordionGroup>
</Accordion>Accordion with Icons
Add emoji or icon elements before the title:
Props API Documentation
AccordionGroup Props
| Prop | Type | Default | Description |
|---|---|---|---|
allowMultiple | boolean | false | Allow multiple items to be open simultaneously |
children | ReactNode | required | Accordion items |
className | string | '' | Additional CSS classes |
Accordion Props
| Prop | Type | Default | Description | |
|---|---|---|---|---|
id | string | auto-generated | Unique identifier (required when inside AccordionGroup) | |
title | `string \ | ReactNode` | required | The accordion trigger label |
defaultOpen | boolean | false | Whether the accordion starts expanded | |
icon | ReactNode | undefined | Icon shown before the title | |
children | ReactNode | required | Collapsible content | |
className | string | '' | Additional CSS classes |
Styling with CSS
If you'd rather use plain CSS instead of Tailwind:
Animated Transitions Deep Dive
The animation relies on max-height and opacity transitions. Here's why:
// The key animation technique:
style={{
maxHeight: isOpen ? `${contentHeight}px` : '0px',
opacity: isOpen ? 1 : 0,
}}
className="overflow-hidden transition-all duration-300 ease-in-out"Why max-height instead of height? CSS can't transition from height: 0 to height: auto. By measuring scrollHeight and setting an explicit pixel value for max-height, you get a smooth animation.
Alternative: CSS Grid animation (works in modern browsers):
Accessibility Notes
Here's what makes this accessible:
aria-expanded— The button tells screen readers whether the panel is open or closed.
aria-controls— Links the button to the content it toggles, so assistive tech can jump between them.
role="region"— The panel is marked as a region witharia-labelledbypointing back to the button.
- Keyboard interaction — It's a native
<button>, so Enter and Space work out of the box.
- Focus management —
focus-visiblestyles show clear focus rings for keyboard users without affecting mouse users.
- Content accessibility — When collapsed,
overflow: hiddenwith zero height hides content visually. The final closed state keeps it hidden from screen readers too.
- Motion sensitivity — Add a
prefers-reduced-motionquery for users who get motion sickness:
@media (prefers-reduced-motion: reduce) {
.accordion-content {
transition: none;
}
.accordion-chevron {
transition: none;
}
}Advanced: Searchable FAQ Accordion
For long FAQ lists, add a search filter:
Summary
The Accordion is all about progressive disclosure — show titles upfront, reveal details on demand. With smooth animations, ARIA attributes, and flexible group/standalone modes, this component makes long MDX docs way easier to navigate.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Building an Accordion/Collapsible Component.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this MDX Tutorial topic.
Search Terms
mdx-tutorial, mdx tutorial, mdx, tutorial, components, accordion, component, building an accordion/collapsible component
Related MDX Tutorial Topics