Accordion
Accordions organize content into collapsible sections, allowing users to expand and view information progressively without overwhelming the interface.
import {Accordion} from "@qualcomm-ui/react/accordion"Usage
- The accordion requires each of its items to have a unique
valueinput. - The accordion is keyboard-navigable once focused. Arrow keys can be used to move to the next or previous item. Home and End keys can be used to jump to the first or last item, respectively.
Examples
Simple
Here's a typical usage example that uses the shorthand syntax for the item.
Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas.
<Accordion.Root className="w-96" defaultValue={["a"]}>
<Accordion.Item
secondaryText="Secondary text"
text="Accordion Text 1"
value="a"
>
<LoremIpsum />
</Accordion.Item>
<Accordion.Item
secondaryText="Secondary text"
text="Accordion Text 2"
value="b"
>
<LoremIpsum />
</Accordion.Item>
</Accordion.Root>
Composite
The following example is equivalent to the previous example, but uses the composite approach.
Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas.
<Accordion.ItemRoot value="a">
<Accordion.ItemTrigger>
<Accordion.ItemText>Accordion Text 1</Accordion.ItemText>
<Accordion.ItemSecondaryText>
Secondary text
</Accordion.ItemSecondaryText>
<Accordion.ItemIndicator />
</Accordion.ItemTrigger>
<Accordion.ItemContent>
<LoremIpsum />
</Accordion.ItemContent>
</Accordion.ItemRoot>
Composite Layout
Use the composite form only when the simple approach can't achieve your desired layout or behavior. The following example demonstrates how to display the expand/collapse indicator at the start of the trigger by changing its DOM position.
<Accordion.Root className="w-96">
{items.map((item) => (
<Accordion.ItemRoot key={item.value} value={item.value}>
<Accordion.ItemTrigger>
<Accordion.ItemIndicator />
<Accordion.ItemText>{item.text}</Accordion.ItemText>
</Accordion.ItemTrigger>
<Accordion.ItemContent>{item.content}</Accordion.ItemContent>
</Accordion.ItemRoot>
))}
</Accordion.Root>
Multiple
By default, only a single accordion section can be open at a time. Setting multiple allows multiple sections to be open or closed simultaneously.
<Accordion.Root className="w-96" multiple>
{items.map((item) => (
<Accordion.Item key={item.value} text={item.text} value={item.value}>
{item.content}
</Accordion.Item>
))}
</Accordion.Root>
Collapsible
When multiple is not set, enabling collapsible lets the user close an open accordion item by clicking it again.
<Accordion.Root className="w-96" collapsible defaultValue={["a"]}>
{items.map((item) => (
<Accordion.Item key={item.value} text={item.text} value={item.value}>
{item.content}
</Accordion.Item>
))}
</Accordion.Root>
Default Value
The defaultValue prop allows you to set the initial state for the accordion by specifying which accordion item or items (if multiple is set) should be open by default.
It expects an array of values that should match those passed to each Accordion.Item.
<Accordion.Root className="w-96" defaultValue={["a"]}>
{items.map((item) => (
<Accordion.Item key={item.value} text={item.text} value={item.value}>
{item.content}
</Accordion.Item>
))}
</Accordion.Root>
Disabled
You can disable accordion items by setting their disabled prop. This prevents the item from being interacted with.
You can disable the entire accordion by setting the disabled prop on Accordion.Root.
<Accordion.Root className="w-full" disabled={disabled}>
{items.map((item) => (
<Accordion.Item
key={item.value}
disabled={item.disabled}
text={item.text}
value={item.value}
>
{item.content}
</Accordion.Item>
))}
</Accordion.Root>
Uncontained
Set the uncontained prop when the accordion is not placed inside a container and needs to align flush with adjacent layout elements—such as when positioned directly below a paragraph of text. This prop removes the default horizontal padding from accordion items, allowing them to sit seamlessly within the surrounding content.
<Accordion.Root className="w-96" uncontained>
{items.map((item) => (
<Accordion.Item key={item.value} text={item.text} value={item.value}>
{item.content}
</Accordion.Item>
))}
</Accordion.Root>
Size
Use the size prop to control the size of the accordion items. The available sizes are sm, md (default), and lg.
<Accordion.Root className="w-full" size={size}>
{items.map((item) => (
<Accordion.Item key={item.value} text={item.text} value={item.value}>
{item.content}
</Accordion.Item>
))}
</Accordion.Root>
Secondary Text
Use the Accordion.ItemSecondaryText component to display additional text opposite the trigger title.
<Accordion.Root className="w-96">
{items.map((item) => (
<Accordion.Item
key={item.value}
secondaryText={item.secondaryText}
text={item.text}
value={item.value}
>
{item.content}
</Accordion.Item>
))}
</Accordion.Root>
Icon
Pass an icon to the icon prop on the Accordion.ItemTrigger element to display it next to the trigger title.
<Accordion.Root className="w-96">
{items.map((item) => (
<Accordion.Item
key={item.value}
icon={FileChartColumn}
text={item.text}
value={item.value}
>
{item.content}
</Accordion.Item>
))}
</Accordion.Root>
UX considerations
In order to prevent visual confusion, only one icon can appear next to the trigger title. If you place the indicator at the start, the icon prop will be ignored.
Controlled State
The Accordion follows our controlled state pattern with these three props:
- value - the controlled value that determines which accordion items are open.
- onValueChange - callback fired when the value changes:
(value: string[]) => void - defaultValue - initial state for uncontrolled mode
Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas.
<Accordion.Root
multiple
onValueChange={setCurrentValue}
value={currentValue}
>
<Accordion.Item text="Accordion Text 1" value="a">
<LoremIpsum />
</Accordion.Item>
<Accordion.Item text="Accordion Text 2" value="b">
<LoremIpsum />
</Accordion.Item>
<Accordion.Item text="Accordion Text 3" value="c">
<LoremIpsum />
</Accordion.Item>
</Accordion.Root>
Focus Callback
The onFocusChange prop allows you to listen for focus events on the accordion's items.
<Accordion.Root
defaultValue={["a"]}
multiple
onFocusChange={(value) => setCurrentValue(value || "")}
>
{items.map((item) => (
<Accordion.Item key={item.value} text={item.text} value={item.value}>
{item.content}
</Accordion.Item>
))}
</Accordion.Root>
Shortcuts
Item Content
The Accordion.ItemContent component is a shortcut for the following:
<AccordionItemContentAnimator>
<AccordionItemContentBody>{children}</AccordionItemContentBody>
</AccordionItemContentAnimator>Item Shorthand
The Accordion.Item component is a shortcut for the following:
<Accordion.ItemRoot>
<Accordion.ItemTrigger>
<Accordion.ItemText>{props.text}</Accordion.ItemText>
{props.secondaryText ? (
<Accordion.ItemSecondaryText>
{props.secondaryText}
</Accordion.ItemSecondaryText>
) : null}
<Accordion.ItemIndicator />
</Accordion.ItemTrigger>
<Accordion.ItemContent>{props.children}</Accordion.ItemContent>
</Accordion.ItemRoot>Explorer
Component Anatomy
Hover to highlight, click to view API
API
<Accordion.Root>
booleanstring[]
'ltr' | 'rtl'
booleanboolean(
value: string,
) => void
(
value: string[],
) => void
| ReactElement
| ((
props: object,
) => ReactElement)
| 'sm'
| 'md'
| 'lg'
booleanstring[]
data-accordion-part'root'<Accordion.Item>
<div> element by default.stringbooleanLucideIconstring| ReactElement
| ((
props: object,
) => ReactElement)
data-accordion-part'item'data-disableddata-focusdata-state| 'open'
| 'closed'
<Accordion.ItemTrigger>
<button>
element by default.LucideIconstring| ReactElement
| ((
props: object,
) => ReactElement)
data-accordion-part'item-trigger'data-disableddata-focusdata-ownedbystringdata-state| 'open'
| 'closed'
<Accordion.ItemText>
<span> element by default.data-accordion-part'item-text'data-disableddata-focusdata-state| 'open'
| 'closed'
<Accordion.ItemSecondaryText>
<span> element by default.| ReactElement
| ((
props: object,
) => ReactElement)
data-accordion-part'item-secondary-text'data-disableddata-focusdata-state| 'open'
| 'closed'
<Accordion.ItemIndicator>
<div> element by default.| LucideIcon
| ReactNode
| ReactElement
| ((
props: object,
) => ReactElement)
data-accordion-part'item-indicator'data-disableddata-focusdata-state| 'open'
| 'closed'
<Accordion.ItemContent>
<div> element
by default.<CoreCollapsible.RootProvider open={open}>
<Accordion.ItemContentAnimator>
<Accordion.ItemContentBody>
{props.children}
</Accordion.ItemContentBody>
</Accordion.ItemContentAnimator>
</CoreCollapsible.RootProvider>
| ReactElement
| ((
props: object,
) => ReactElement)
data-accordion-part'item-content'data-disableddata-expandeddata-focusdata-state| 'open'
| 'closed'
<Accordion.ItemContentAnimator>
<div> element by default.string| ReactElement
| ((
props: object,
) => ReactElement)
<Accordion.ItemContentBody>
<div> element by
default.| ReactElement
| ((
props: object,
) => ReactElement)
<div>element by default.