Accordion Compound Component

Overview

The Accordion is a classic UI element that uses the compound component pattern to create collapsible sections. It consists of multiple items, each with a header that controls visibility of its content.

Example

What is React?
What are Compound Components?
How do Compound Components work?

Code Implementation

// Accordion.tsx
import React, { createContext, useContext, useState, ReactNode } from 'react';

// Create context for the accordion
type AccordionContextType = {
  expandedItems: Record<string, boolean>;
  toggleItem: (id: string) => void;
  isItemExpanded: (id: string) => boolean;
  allowMultiple: boolean;
};

const AccordionContext = createContext<AccordionContextType | undefined>(undefined);

// Hook to use accordion context
const useAccordion = () => {
  const context = useContext(AccordionContext);
  if (!context) {
    throw new Error('Accordion components must be used within an Accordion');
  }
  return context;
};

// Main Accordion component
const Accordion = ({ children, allowMultiple = false, className = '' }) => {
  const [expandedItems, setExpandedItems] = useState({});

  const toggleItem = (id) => {
    setExpandedItems(prev => {
      if (!allowMultiple) {
        // If only one item can be expanded at a time, close others
        return { [id]: !prev[id] };
      }
      return { ...prev, [id]: !prev[id] };
    });
  };

  const isItemExpanded = (id) => !!expandedItems[id];

  return (
    <AccordionContext.Provider value={{ expandedItems, toggleItem, isItemExpanded, allowMultiple }}>
      <div className={`divide-y divide-gray-200 border border-gray-200 rounded-md ${className}`}>
        {children}
      </div>
    </AccordionContext.Provider>
  );
};

// Item component and sub-components...
// Attach sub-components to Accordion
Accordion.Item = Item;
Accordion.Header = Header;
Accordion.Content = Content;

export default Accordion;

Key Features

  • Shared state using Context API to track which panels are expanded
  • Option to allow multiple panels to be open simultaneously
  • Customizable styling for each part of the accordion
  • Clear component composition with semantic item, header, and content components
  • Each accordion item maintains its own state within the parent context