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.

How long does shipping take?
Orders arrive within 3–5 business days.
Can I return an item?
Is there a warranty?

Import#

typescript
import { Accordion } from "@reactberry/system/blocks";

Usage#

typescript
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.

1. Create an account
Sign up with your work email.
2. Invite your team
3. Start a project

Leading icon with saved state#

Use iconPosition="start" for tree-like lists. With persistKey, open items survive a page reload.

General
Privacy

Static and disabled rows#

Use hideIcon for a row that never expands, such as a summary, and disabled for items that are temporarily unavailable.

Summary
Details
Archived

API#

Accordion#

PropTypeDefaultDescription
items*
AccordionItem[]
—

Items to render. Each has an id, a trigger, content, and optional disabled and hideIcon.

allowMultiple
boolean
true

When false, opening an item closes the others.

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 localStorage under accordion-<key>. Stored values replace defaultOpen.

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 size (defaults to "1.75em").

containerProps
{ [key: string]: any; }
{}

Props spread onto the outer column Box.

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#

PropTypeDefaultDescription
id*
string
—

Unique id, used by defaultOpen, onToggle and persistKey.

trigger*
ReactNode
—

Content of the clickable row.

content*
ReactNode
—

Content shown when the item is open.

disabled
boolean
—

Renders at 50% opacity with a not-allowed cursor and ignores clicks.

hideIcon
boolean
—

Hides the icon, uses a default cursor, and never expands.

Accessibility#

  • Trigger rows are clickable div elements. They have no button role, no aria-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: 180 degrees when open at the end position, and from -90 to 0 degrees at the start position.
  • fontSize and spacing are declared in the props type but are not used.