Introducing PrimeReact v11-alpha 🎉Discover Now

useAccordion

Hooks that manage accordion state, keyboard navigation, and ARIA attributes.

PrimeReact is a rich set of open source UI components for React.
basic-demo

Usage#

import { useAccordion, useAccordionPanel } from '@primereact/headless/accordion';
const accordion = useAccordion({ defaultValue: '1' });
const { rootProps } = accordion;
 
const { panelProps, headerProps, triggerProps, contentProps, indicatorProps, state } = useAccordionPanel({
    value: '1',
    context: accordion
});
 
<div {...rootProps}>
    <div {...panelProps}>
        <div {...headerProps}>
            <button {...triggerProps}>
                <span {...indicatorProps} />
            </button>
        </div>
        {state.open && <div {...contentProps}></div>}
    </div>
</div>;

useAccordion manages root state while useAccordionPanel consumes that context to return prop objects for each panel element — see Primitive for a component-based API.

Features#

  • Two-hook architecture — useAccordion owns root state and keyboard focus cycling; useAccordionPanel consumes its context to render individual panels
  • Single or multiple expansion — one open panel at a time or an array of open keys, switchable via the multiple flag
  • Controlled or uncontrolled — drive the active key(s) from outside or let the hook manage its own state
  • Focus-triggered expansion — opt into openOnFocus to open a panel the moment its trigger is focused via keyboard
  • Imperative controls — updateValue() toggles a key and isItemActive() checks open state from custom code paths
  • Full render control — state.open lets you conditionally mount content, pair with CSS, or wire up animation hooks

Working with callbacks#

Controlled active panel#

Drive the open panel from outside state by pairing value with onValueChange.

const [value, setValue] = React.useState<string | null>('1');
 
const accordion = useAccordion({
    value,
    onValueChange: (e) => setValue(e.value)
});

onValueChange receives { originalEvent, value } — value is a single key in single mode or the new array in multiple mode.

Multiple open panels#

Set multiple to keep several panels open at once. Both value and defaultValue become arrays.

const accordion = useAccordion({
    multiple: true,
    defaultValue: ['1', '2'],
    onValueChange: (e) => console.log(e.value) // string[]
});

Imperative toggling from custom UI#

Use updateValue to toggle panels from buttons that live outside the accordion tree, such as a sidebar or toolbar.

const accordion = useAccordion({ multiple: true });
 
<button onClick={(e) => accordion.updateValue(e, '3')}>Toggle section 3</button>;
 
if (accordion.isItemActive('2')) {
    // run logic only when panel 2 is open
}

In single mode updateValue toggles between the key and null; in multiple mode it adds or removes the key from the array.

Animated enter/leave with state.open#

Because the hook leaves content rendering to you, pair state.open with a motion primitive to animate transitions.

const { contentProps, state } = useAccordionPanel({ value: '1', context: accordion });
 
<AnimatePresence>
    {state.open && (
        <motion.div {...contentProps} initial={{ height: 0 }} animate={{ height: 'auto' }} exit={{ height: 0 }}>
            Panel content
        </motion.div>
    )}
</AnimatePresence>;

For a built-in approach, use the useMotion hook alongside state.open.

Styling with data attributes#

Every prop object includes data-scope="accordion" and a data-part attribute. State-dependent attributes are applied automatically so styling can stay in CSS.

ScopePartStates
accordionpaneldata-open, data-closed, data-disabled
accordiontriggerdata-content-open, data-content-closed
accordioncontentdata-open, data-closed
[data-scope='accordion'][data-part='trigger'] {
    font-weight: 600;
}
 
[data-scope='accordion'][data-part='content'][data-open] {
    animation: slideDown 200ms ease-out;
}
 
[data-scope='accordion'][data-part='content'][data-closed] {
    animation: slideUp 200ms ease-out;
}
 
[data-scope='accordion'][data-part='panel'][data-disabled] {
    opacity: 0.5;
}
 
[data-scope='accordion'][data-part='trigger'][data-content-open] {
    color: blue;
    font-weight: 700;
}

API#

useAccordion#

NameTypeDefault
defaultValuestring | number | (string | number)[]—
Default value of the active panel or an array of values in multiple mode.
valuestring | number | (string | number)[]—
Value of the active panel or an array of values in multiple mode.
multiplebooleanfalse
When enabled, multiple tabs can be activated at the same time.
disabledbooleanfalse
When disabled, the component cannot be interacted with.
tabIndexnumber0
Index of the element in tabbing order.
openOnFocusbooleanfalse
When enabled, the accordion panel will be opened on focus.
onValueChange(event: useAccordionChangeEvent) => void—
Callback fired when the accordion's value changes.

useAccordionPanel#

NameTypeDefault
valuestring | number—
Unique value of the panel.
disabledbooleanfalse
Whether the panel is disabled.
contextuseAccordionInstance—
The parent accordion instance providing state and methods.

Accessibility#

Arrow keys move between headers, Home/End jump to first/last, and Enter or Space toggles the focused panel. See Primitive for full WAI-ARIA compliance details.