Skip to content

Accordion

A responsive and accessible accordion component that allows users to expand and collapse content sections. Perfect for FAQs, feature lists, and organizing content in a compact space.

Component Code

import React, { useState } from "react";
import { ChevronDownIcon } from "@heroicons/react/24/outline";
const Accordion = ({ items, allowMultiple = true, className = "" }) => {
const [openItems, setOpenItems] = useState(new Set());
const toggleItem = (index) => {
const newOpenItems = new Set(openItems);
if (allowMultiple) {
if (newOpenItems.has(index)) {
newOpenItems.delete(index);
} else {
newOpenItems.add(index);
}
} else {
if (newOpenItems.has(index)) {
newOpenItems.clear();
} else {
newOpenItems.clear();
newOpenItems.add(index);
}
}
setOpenItems(newOpenItems);
};
return (
<div className={`space-y-2 ${className}`}>
{items.map((item, index) => (
<div
key={index}
className="border border-gray-200 rounded-lg overflow-hidden shadow-sm"
>
<button
onClick={() => toggleItem(index)}
className="w-full px-6 py-4 text-left bg-white hover:bg-gray-50 focus:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-inset transition-colors duration-200 flex items-center justify-between"
aria-expanded={openItems.has(index)}
aria-controls={`accordion-content-${index}`}
>
<span className="text-gray-900 font-medium">{item.title}</span>
<ChevronDownIcon
className={`w-5 h-5 text-gray-500 transition-transform duration-200 ${
openItems.has(index) ? "rotate-180" : ""
}`}
/>
</button>
<div
id={`accordion-content-${index}`}
className={`transition-all duration-300 ease-in-out ${
openItems.has(index)
? "max-h-96 opacity-100"
: "max-h-0 opacity-0"
} overflow-hidden`}
>
<div className="px-6 py-4 bg-gray-50 text-gray-700 border-t border-gray-200">
{item.content}
</div>
</div>
</div>
))}
</div>
);
};
export default Accordion;

Usage Example

import React from "react";
import Accordion from "./Accordion";
const App = () => {
const faqItems = [
{
title: "What is React?",
content:
"React is a JavaScript library for building user interfaces. It allows you to create reusable UI components and manage application state efficiently.",
},
{
title: "How do I get started with React?",
content:
"You can start by creating a new React app using Create React App or Vite. Then learn about components, JSX, and state management.",
},
{
title: "What are React Hooks?",
content:
"Hooks are functions that let you use state and other React features in functional components. Common hooks include useState, useEffect, and useContext.",
},
{
title: "How do I style React components?",
content:
"You can style React components using CSS modules, styled-components, Tailwind CSS, or traditional CSS files.",
},
];
return (
<div className="max-w-4xl mx-auto p-6">
<h1 className="text-3xl font-bold mb-8 text-gray-900">
Frequently Asked Questions
</h1>
<Accordion items={faqItems} />
</div>
);
};
export default App;

Props

PropTypeDefaultDescription
itemsArray<{title: string, content: string}>requiredArray of accordion items with title and content
allowMultiplebooleantrueWhether multiple items can be open at the same time
classNamestring''Additional CSS classes for the accordion container

Features

  • Responsive Design: Works perfectly on all screen sizes
  • Smooth Animations: CSS transitions for expand/collapse actions
  • Keyboard Accessible: Full keyboard navigation support
  • Customizable: Easy to modify styles and behavior
  • Multiple or Single Mode: Control whether multiple items can be open
  • Clean Design: Modern, minimal styling with Tailwind CSS

Installation

First, make sure you have Tailwind CSS installed in your project. Then install Heroicons for the chevron icon:

Terminal window
npm install @heroicons/react

If you prefer not to use Heroicons, you can replace the ChevronDownIcon with any other icon or even a simple Unicode character like .

Customization

Different Styles

// Bordered style
<Accordion
items={items}
className="border-2 border-gray-300 rounded-xl"
/>
// Card style with shadow
<Accordion
items={items}
className="shadow-lg rounded-xl bg-white"
/>
// Colored theme
<Accordion
items={items}
className="bg-blue-50 border border-blue-200 rounded-lg"
/>

Without Icons

If you want to remove the chevron icon, simply remove the ChevronDownIcon import and the icon element from the button.

Notes

  • The component uses max-h-96 for the expanded state - adjust this based on your content length
  • Smooth transitions are handled with Tailwind’s transition-all and duration-300
  • The component is fully controlled by React state with no external dependencies except Heroicons
  • Accessibility features are built-in with proper ARIA attributes