Controlling state
From above Accordion
If you want to programmatically open or close accordion items from a component that is
above Accordion
in the React tree, you could use the ControlledAccordion
and
useAccordionProvider
.
The value returned from useAccordionProvider
contains a toggle
function which can be
used to open or close any accordion items. This value should also be given to the
providerValue
prop of the ControlledAccordion
component.
The toggle
function accepts two parameters. The first parameter is the itemKey
prop of
any accordion items to toggle. The second parameter specifies whether to open or close an
item using a boolean
value, or to toggle between the two states if the parameter is
omitted.
import {
ControlledAccordion,
AccordionItem,
useAccordionProvider
} from '@szhsin/react-accordion';
export default function Example() {
const providerValue = useAccordionProvider({
allowMultiple: true,
transition: true,
transitionTimeout: 250
});
// Destructuring `toggle` and `toggleAll` from `providerValue`
const { toggle, toggleAll } = providerValue;
return (
<div>
<div className="buttons">
<button
className="btn"
// Toggle between open and close by omitting the second parameter
onClick={() => toggle('item-1')}
>
Toogle the first item
</button>
<button
className="btn"
// Open rather than toggling
onClick={() => toggle('item-3', true)}
>
Open the last item
</button>
<button
className="btn"
onClick={() => toggleAll(true)}
>
Open all items
</button>
<button
className="btn"
onClick={() => toggleAll(false)}
>
Close all items
</button>
<button
className="btn"
// Omitting the boolean parameter means toggling
onClick={() => toggleAll()}
>
Toggle all items
</button>
</div>
<ControlledAccordion
// Forward the `providerValue` directly to `ControlledAccordion`
providerValue={providerValue}
>
<AccordionItem
header="What is Lorem Ipsum?"
// Set an explicit `itemKey`
itemKey="item-1"
>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
do eiusmod tempor incididunt ut labore et dolore magna
aliqua.
</p>
<button
className="btn"
// It also works within the `AccordionItem` children
onClick={() => toggle('item-3')}
>
Toggle the last item
</button>
</AccordionItem>
<AccordionItem header="Where does it come from?">
Quisque eget luctus mi, vehicula mollis lorem. Proin fringilla
vel erat quis sodales. Nam ex enim, eleifend venenatis lectus
vitae, accumsan auctor mi.
</AccordionItem>
<AccordionItem
header="Why do we use it?"
// Set an explicit `itemKey`
itemKey="item-3"
>
Suspendisse massa risus, pretium id interdum in, dictum sit
amet ante. Fusce vulputate purus sed tempus feugiat.
</AccordionItem>
</ControlledAccordion>
</div>
);
}
The itemKey
prop of AccordionItem
is not required to be globally unique, but it should
be unique among its sibling AccordionItem
components.
Also, you don't need to specify the itemKey
prop for an item if you don't want to
programmatically toggle it.
From underneath Accordion
To programmatically open or close accordion items or access the state from a component
that is underneath Accordion
in the React tree, use the useAccordionState
hook.
import {
Accordion,
AccordionItem,
useAccordionState
} from '@szhsin/react-accordion';
const MyItem = () => {
const { getItemState, toggle, toggleAll } = useAccordionState();
return (
<AccordionItem header="My custom accordion item" initialEntered>
<p>
{/* Accessing item state by providing an `itemKey` */}
Next item expanded: {getItemState('next').isEnter.toString()}
</p>
<div className="buttons">
<button className="btn" onClick={() => toggle('next')}>
Toggle next item
</button>
<button className="btn" onClick={() => toggleAll(false)}>
Close all items
</button>
</div>
</AccordionItem>
);
};
export default function Example() {
return (
<Accordion allowMultiple>
<MyItem />
<AccordionItem
header="What is Lorem Ipsum?"
itemKey="next"
>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
</AccordionItem>
</Accordion>
);
}
If you want to access and control state of the current item, there is a simpler way to achieve it using the render prop pattern.