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
Prop | Type | Default | Description |
---|---|---|---|
items | Array<{title: string, content: string}> | required | Array of accordion items with title and content |
allowMultiple | boolean | true | Whether multiple items can be open at the same time |
className | string | '' | 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:
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
andduration-300
- The component is fully controlled by React state with no external dependencies except Heroicons
- Accessibility features are built-in with proper ARIA attributes