Accordion
Expand and collapse a list of items with animated content and optional localStorage persistence.
Accordion is a client component that renders a vertical list of items, each with a clickable trigger row and animated collapsible content. Use it for FAQs, settings groups and other content that people scan before reading. Open state can be persisted to localStorage through the persistKey prop.
Import#
import { Accordion } from "@reactberry/system/blocks";
Usage#
import { Accordion } from "@reactberry/system/blocks";
import { Text } from "@reactberry/system/elements";
const faqs = [
{
id: "shipping",
trigger: <Text fontWeight="600">How long does shipping take?</Text>,
content: <Text py="small">Orders arrive within 3–5 business days.</Text>,
},
{
id: "returns",
trigger: <Text fontWeight="600">Can I return an item?</Text>,
content: <Text py="small">Returns are accepted within 30 days.</Text>,
},
];
export default function Faq() {
return (
<Accordion
items={faqs}
allowMultiple={false}
defaultOpen={["shipping"]}
headerProps={{ py: "small" }}
/>
);
}
Examples#
One item at a time#
Set allowMultiple={false} when items are steps or alternatives, so opening one closes the others.
Leading icon with saved state#
Use iconPosition="start" for tree-like lists. With persistKey, open items survive a page reload.
Static and disabled rows#
Use hideIcon for a row that never expands, such as a summary, and disabled for items that are temporarily unavailable.
API#
Accordion#
| Prop | Type | Default | Description |
|---|---|---|---|
items* | AccordionItem[] | — | Items to render. Each has an |
allowMultiple | boolean | true | When |
defaultOpen | string[] | [] | Ids of the items open on first render. |
onToggle | ((itemId: string, isOpen: boolean, openItems: string[]) => void) | — | Called after each toggle with the item id, its new state and all open ids. |
fontSize | string | — | Declared but not used. |
spacing | string | — | Declared but not used. |
persistKey | string | — | Persist open ids to |
iconPosition | "start""end" | "end" | Side of the trigger row the icon is placed on. |
icon | ElementType<any, keyof IntrinsicElements> | ƒ() | Icon rendered in the trigger (defaults to a downward chevron). |
iconSize | string | number | 1.75em | Size of the trigger icon, passed to Box's |
containerProps | { [key: string]: any; } | {} | Props spread onto the outer column |
itemProps | { [key: string]: any; } | {} | Props spread onto each item wrapper. |
headerProps | { [key: string]: any; } | {} | Props spread onto each trigger row. |
Remaining props are accepted by the type but not spread onto any element.
AccordionItem#
| Prop | Type | Default | Description |
|---|---|---|---|
id* | string | — | Unique id, used by |
trigger* | ReactNode | — | Content of the clickable row. |
content* | ReactNode | — | Content shown when the item is open. |
disabled | boolean | — | Renders at 50% opacity with a |
hideIcon | boolean | — | Hides the icon, uses a default cursor, and never expands. |
Accessibility#
- Trigger rows are clickable
divelements. They have nobuttonrole, noaria-expanded, and no keyboard handling, so items can't be opened with the keyboard or identified as expandable by screen readers.
Notes#
- The icon rotates to indicate state:
180degrees when open at the end position, and from-90to0degrees at the start position. fontSizeandspacingare declared in the props type but are not used.