Skip to main content

Creating AccordionItem

Second, create an AccordionItem component with the useAccordionItem and useAccordionItemEffect hook exported from the library.

Without height transition

Use the following code if you don't need the height transition for expanding and collapsing items.

import {
useAccordionItem,
useAccordionItemEffect
} from '@szhsin/react-accordion';
import ChevronDown from '@site/static/img/chevron-down.svg';
import styles from '../accordion/styles.module.css';

const AccordionItem = ({
header,
children,
itemKey,
initialEntered,
disabled
}: {
header: React.ReactNode;
children: React.ReactNode;
itemKey?: string | number;
initialEntered?: boolean;
disabled?: boolean;
}) => {
const { itemRef, state, toggle } =
useAccordionItemEffect<HTMLDivElement>({
itemKey,
initialEntered,
disabled
});
const { buttonProps, panelProps } = useAccordionItem({
state,
toggle,
disabled
});
const { status, isMounted, isEnter } = state;

return (
<div className={styles.item} ref={itemRef}>
{/* Choose a heading level that is appropriate for the information
architecture of your page */}
<h3 style={{ margin: 0 }}>
<button
className={isEnter ? styles.buttonExpanded : styles.button}
type="button"
{...buttonProps}
>
{header}
<ChevronDown className={styles.chevron} />
</button>
</h3>
{isMounted && (
<div
className={styles.panel}
style={{
display: status === 'exited' ? 'none' : undefined
}}
{...panelProps}
>
{children}
</div>
)}
</div>
);
};

export default AccordionItem;

Height transition

Use the useHeightTransition hook and add a wrapping div around the accordion item children if you want the height transition for expanding and collapsing items.

import {
useAccordionItem,
useAccordionItemEffect,
useHeightTransition
} from '@szhsin/react-accordion';
import ChevronDown from '@site/static/img/chevron-down.svg';
import styles from '../accordion/styles.module.css';

const AccordionItem = ({
header,
children,
itemKey,
initialEntered,
disabled
}: {
header: React.ReactNode;
children: React.ReactNode;
itemKey?: string | number;
initialEntered?: boolean;
disabled?: boolean;
}) => {
const { itemRef, state, toggle } =
useAccordionItemEffect<HTMLDivElement>({
itemKey,
initialEntered,
disabled
});
const { buttonProps, panelProps } = useAccordionItem({
state,
toggle,
disabled
});

const [transitionStyle, panelRef] =
useHeightTransition<HTMLDivElement>(state);

const { status, isMounted, isEnter } = state;

return (
<div className={styles.item} ref={itemRef}>
<h3 style={{ margin: 0 }}>
<button
className={isEnter ? styles.buttonExpanded : styles.button}
type="button"
{...buttonProps}
>
{header}
<ChevronDown className={styles.chevron} />
</button>
</h3>
{isMounted && (
// Add an extra `div` around the panel `div` for the
// height transition to work as intended
<div
className={styles.content}
style={{
display: status === 'exited' ? 'none' : undefined,
...transitionStyle
}}
>
<div
className={styles.panel}
ref={panelRef}
{...panelProps}
>
{children}
</div>
{/* Closing tag of the extra `div` */}
</div>
)}
</div>
);
};

export default AccordionItem;