Accordion
Accordion components allow users to show and hide sections of content. Use them for FAQs, settings panels, or any UI where space is limited and content can be progressively disclosed.
Accordion Playground
What payment methods do you accept?
How do I cancel my subscription?
Can I upgrade or downgrade my plan?
Installation
You can add the accordion component to your project manually:
Install the following dependencies:
npm install class-variance-authority clsx tailwind-merge @phosphor-icons/react @react-aria/focus @react-aria/interactionsCopy and paste the following code into your project.
Update the import paths to match your project setup.
Update the import aliases (e.g. @/components, @/utils) in the copied files to match your project's path configuration.
Basic Usage
A single AccordionItem works as a standalone component:
import { AccordionItem } from '@versaui/ui/components/Accordion';
function Example() {
return (
<AccordionItem title="What payment methods do you accept?">
We accept all major credit cards, PayPal, and bank transfers.
</AccordionItem>
);
}Accordion Group
Use the Accordion wrapper to coordinate multiple items. Set singleOpen to allow only one item open at a time:
import { Accordion, AccordionItem } from '@versaui/ui/components/Accordion';
function FAQ() {
return (
<Accordion singleOpen gap={12}>
<AccordionItem id="q1" title="What payment methods do you accept?">
We accept all major credit cards, PayPal, and bank transfers.
</AccordionItem>
<AccordionItem id="q2" title="How do I cancel my subscription?">
You can cancel anytime from your account settings.
</AccordionItem>
<AccordionItem id="q3" title="Can I upgrade my plan?">
Yes, upgrades are prorated and take effect immediately.
</AccordionItem>
</Accordion>
);
}For multiple items open simultaneously, omit the singleOpen prop:
<Accordion gap={12}>
<AccordionItem id="section1" title="Section 1">Content 1</AccordionItem>
<AccordionItem id="section2" title="Section 2">Content 2</AccordionItem>
</Accordion>Controlled State
For external state control, use isOpen and onOpenChange:
import { useState } from 'react';
import { AccordionItem } from '@versaui/ui/components/Accordion';
function ControlledExample() {
const [isOpen, setIsOpen] = useState(false);
return (
<AccordionItem
isOpen={isOpen}
onOpenChange={setIsOpen}
title="Controlled Section"
>
This accordion is controlled by parent state.
</AccordionItem>
);
}Variants
Size
Two sizes are available — default and large:
<AccordionItem size="default" title="Default Size">
Standard padding and typography.
</AccordionItem>
<AccordionItem size="large" title="Large Size">
Larger padding and typography for prominent sections.
</AccordionItem>Container
Set container={false} for a borderless variant with only a bottom divider:
<AccordionItem container={false} title="Borderless Section">
This variant has no container background.
</AccordionItem>Rich Content
The accordion body accepts any React content:
<AccordionItem title="Account Settings">
<p>Update your profile information below.</p>
<button onClick={() => console.log('clicked')}>
Edit Profile
</button>
</AccordionItem>Accessibility
The Accordion component is fully accessible:
- Keyboard navigation: Press
EnterorSpaceto toggle when focused - Screen readers: Trigger announces expanded/collapsed state via
aria-expanded - Focus management: Visual focus ring appears when navigating via keyboard
- Semantic structure: Uses
role="button"for trigger,role="region"for content
AccordionItem Props
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | — | Required. Header text. |
children | ReactNode | — | Required. Content revealed when expanded. |
size | 'default' | 'large' | 'default' | Controls padding and typography. |
container | boolean | true | Show background/border or only bottom divider. |
isOpen | boolean | — | Controlled open state. |
defaultOpen | boolean | false | Initial open state (uncontrolled). |
onOpenChange | (open: boolean) => void | — | Callback when open state changes. |
disabled | boolean | false | Prevents interaction. |
id | string | auto | Unique ID for group coordination. |
className | string | '' | Additional CSS classes. |
Accordion (Group) Props
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Required. AccordionItem components. |
singleOpen | boolean | false | Only one item open at a time. |
gap | number | 0 | Gap between items in pixels. |
defaultOpenItems | string[] | [] | IDs of initially open items. |
openItems | string[] | — | Controlled array of open item IDs. |
onOpenItemsChange | (ids: string[]) => void | — | Callback when open items change. |
className | string | '' | Additional CSS classes. |