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;