Skip to main content

Accordion

The Accordion components (AccordionGroup and AccordionItem) allow you to create expandable panels for organizing content. These are part of the React package and use the Gaya design system.

Installation

npm install @naturacosmeticos/natds-react

Usage

import { AccordionGroup, AccordionItem } from '@naturacosmeticos/natds-react';
import { useState } from 'react';

function AccordionExample() {
  const [activeIndex, setActiveIndex] = useState(null);

  const handleToggle = (index) => {
    setActiveIndex(activeIndex === index ? null : index);
  };

  return (
    <AccordionGroup>
      <AccordionItem
        title="Section 1"
        isActive={activeIndex === 0}
        onClick={() => handleToggle(0)}
      >
        Content for section 1
      </AccordionItem>
      <AccordionItem
        title="Section 2"
        isActive={activeIndex === 1}
        onClick={() => handleToggle(1)}
      >
        Content for section 2
      </AccordionItem>
      <AccordionItem
        title="Section 3"
        isActive={activeIndex === 2}
        onClick={() => handleToggle(2)}
      >
        Content for section 3
      </AccordionItem>
    </AccordionGroup>
  );
}

Accordion Variants

Regular Accordion

Default accordion with standard styling:
<AccordionGroup>
  <AccordionItem
    title="Regular Item"
    color="regular"
    isActive={isActive}
    onClick={handleToggle}
  >
    This is a regular accordion item with standard background.
  </AccordionItem>
</AccordionGroup>

Primary Colored Accordion

Accordion with primary color styling:
<AccordionGroup>
  <AccordionItem
    title="Primary Item"
    color="primary"
    isActive={isActive}
    onClick={handleToggle}
  >
    This item uses the primary brand color.
  </AccordionItem>
</AccordionGroup>

With Legend/Subtitle

Add a legend (subtitle) to accordion items:
<AccordionItem
  title="Section Title"
  legend="Additional information"
  isActive={isActive}
  onClick={handleToggle}
>
  Content goes here
</AccordionItem>

Disabled Accordion

Prevent interaction with disabled state:
<AccordionItem
  title="Disabled Item"
  isDisabled={true}
  isActive={false}
  onClick={handleToggle}
>
  This content won't be accessible
</AccordionItem>

Controlled vs Uncontrolled

Controlled Accordion

Manage accordion state externally:
function ControlledAccordion() {
  const [expanded, setExpanded] = useState(0);

  return (
    <AccordionGroup>
      {items.map((item, index) => (
        <AccordionItem
          key={index}
          title={item.title}
          isActive={expanded === index}
          onClick={() => setExpanded(index)}
        >
          {item.content}
        </AccordionItem>
      ))}
    </AccordionGroup>
  );
}

Multiple Panels Open

Allow multiple accordion items to be open simultaneously:
function MultipleAccordion() {
  const [openItems, setOpenItems] = useState([]);

  const handleToggle = (index) => {
    setOpenItems(prev => 
      prev.includes(index)
        ? prev.filter(i => i !== index)
        : [...prev, index]
    );
  };

  return (
    <AccordionGroup>
      {items.map((item, index) => (
        <AccordionItem
          key={index}
          title={item.title}
          isActive={openItems.includes(index)}
          onClick={() => handleToggle(index)}
        >
          {item.content}
        </AccordionItem>
      ))}
    </AccordionGroup>
  );
}

With Rich Content

<AccordionGroup>
  <AccordionItem
    title="Product Details"
    legend="View specifications"
    isActive={isActive}
    onClick={handleToggle}
  >
    <div style={{ padding: '16px' }}>
      <h3>Specifications</h3>
      <ul>
        <li>Weight: 500g</li>
        <li>Dimensions: 10x10x5 cm</li>
        <li>Material: Recyclable plastic</li>
      </ul>
      <p>Additional product information...</p>
    </div>
  </AccordionItem>
</AccordionGroup>

Brand Customization

import { BrandTypes } from '@naturacosmeticos/natds-react';

<AccordionItem
  title="Branded Item"
  brand="avon" // or 'natura', 'theBodyShop', etc.
  isActive={isActive}
  onClick={handleToggle}
>
  Content styled according to brand theme
</AccordionItem>

Props

AccordionGroup

children
node
required
AccordionItem components to be grouped together.
className
string
Optional className to be added to the accordion group wrapper.
testID
string
Optional ID for testing purposes.

AccordionItem

title
string
required
The text to display in the accordion header.
onClick
() => void
required
Function to toggle state between open and close.
children
React.ReactNode
required
Content that will be rendered when the AccordionItem is open.
color
'regular' | 'primary'
default:"'regular'"
Defines the style that will be applied to the accordion item.
isActive
boolean
default:"false"
Defines the state of the item (open/close).
isDisabled
boolean
default:"false"
If true, disables click events and changes color style.
legend
string
Optional text used as a subtitle or additional information.
brand
BrandTypes
Brand theme to apply (e.g., ‘avon’, ‘natura’, ‘theBodyShop’).
className
string
Optional className to be added to the accordion item.
testID
string
Optional ID for testing purposes.

Best Practices

  • Always wrap AccordionItem components inside an AccordionGroup
  • Manage accordion state in the parent component for better control
  • Use meaningful titles that clearly indicate the content
  • Consider using legends for additional context
  • Avoid deeply nested accordions as they can confuse users
  • For single-open behavior, track which item is active
  • For multiple-open behavior, use an array to track open items

Accessibility

  • The component automatically adds expand/collapse icons
  • Icons change based on the isActive state
  • Disabled items have appropriate visual styling
  • Ensure sufficient color contrast between text and background
  • Consider adding ARIA attributes for better screen reader support

State Management Patterns

Single Panel Open

const [activeIndex, setActiveIndex] = useState(null);

const handleToggle = (index) => {
  setActiveIndex(activeIndex === index ? null : index);
};

Multiple Panels Open

const [openPanels, setOpenPanels] = useState([]);

const handleToggle = (index) => {
  setOpenPanels(prev =>
    prev.includes(index)
      ? prev.filter(i => i !== index)
      : [...prev, index]
  );
};

Build docs developers (and LLMs) love