Accordion

A vertically stacked set of interactive headings that each reveal an associated section of content.

Features

  • Full keyboard navigation.
  • Can expand one or multiple items.
  • Can be controlled or uncontrolled.

Install the component from your command line.

npm install @radix-ui/react-accordion

Import the components and piece the parts together.

import * as Accordion from '@radix-ui/react-accordion';
export default () => (
<Accordion.Root>
<Accordion.Item>
<Accordion.Header>
<Accordion.Trigger />
</Accordion.Header>
<Accordion.Content />
</Accordion.Item>
</Accordion.Root>
);

Create your styled accordion component from the primitive parts.

Here goes the content for the accordion item 1.

import { styled } from 'path-to/stitches.config';
import * as Accordion from '@radix-ui/react-accordion';
const StyledAccordion = styled(Accordion.Root, {
borderTop: '1px solid gainsboro',
});
const StyledItem = styled(Accordion.Item, {
borderBottom: '1px solid gainsboro',
});
const StyledHeader = styled(Accordion.Header, {
margin: 0,
display: 'flex',
});
const StyledTrigger = styled(Accordion.Trigger, {
backgroundColor: 'transparent',
border: 'none',
padding: 10,
flex: 1,
textAlign: 'left',
});
const StyledContent = styled(Accordion.Content, {
padding: 10,
});
export default () => (
<StyledAccordion type="single" defaultValue="item-1">
<StyledItem value="item-1">
<StyledHeader>
<StyledTrigger>Item 1</StyledTrigger>
</StyledHeader>
<StyledContent>
Here goes the content for the accordion item 1.
</StyledContent>
</StyledItem>
<StyledItem value="item-2">
<StyledHeader>
<StyledTrigger>Item 2</StyledTrigger>
</StyledHeader>
<StyledContent>
Here goes the content for the accordion item 2.
</StyledContent>
</StyledItem>
<StyledItem value="item-3">
<StyledHeader>
<StyledTrigger>Item 3</StyledTrigger>
</StyledHeader>
<StyledContent>
Here goes the content for the accordion item 3.
</StyledContent>
</StyledItem>
</StyledAccordion>
);

Contains all the parts of an accordion.

PropTypeDefault
asenumdiv
type*enumNo default value
valuestringNo default value
defaultValuestringNo default value
onValueChangefunctionNo default value
valuestring[][]
defaultValuestring[][]
onValueChangefunctionNo default value
disabledbooleanfalse

Contains all the parts of a collapsible section.

PropTypeDefault
asenumdiv
disabledbooleanfalse
value*stringNo default value

Wraps an Accordion.Trigger. Use the as prop to update it to the appropriate heading level for your page.

PropTypeDefault
asenumh3

Toggles the collapsed state of its associated item. It should be nested inside of an Accordion.Header.

PropTypeDefault
asenumbutton

Contains the collapsible content for an item.

PropTypeDefault
asenumdiv
forceMountbooleanNo default value

We expose a CSS custom property --radix-accordion-content-height.
Use it to animate the height of the content when it opens/closes.

const slideDown = keyframes({
from: { height: 0 },
to: { height: 'var(--radix-accordion-content-height)' },
});
const slideUp = keyframes({
from: { height: 'var(--radix-accordion-content-height)' },
to: { height: 0 },
});
const StyledContent = styled(Accordion.Content, {
'&[data-state="open"]': {
animation: `${slideDown} 300ms ease-out`,
},
'&[data-state="closed"]': {
animation: `${slideUp} 300ms ease-out`,
},
});

Here goes the content for the accordion item 1.

import { styled } from 'path-to/stitches.config';
import * as Accordion from '@radix-ui/react-accordion';
import { ChevronDownIcon } from '@radix-ui/react-icons';
const StyledAccordion = styled(Accordion.Root, {
borderTop: '1px solid gainsboro',
});
const StyledItem = styled(Accordion.Item, {
borderBottom: '1px solid gainsboro',
});
const StyledHeader = styled(Accordion.Header, {
margin: 0,
display: 'flex',
});
const StyledTrigger = styled(Accordion.Trigger, {
backgroundColor: 'transparent',
border: 'none',
padding: 10,
flex: 1,
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
});
const StyledContent = styled(Accordion.Content, {
padding: 10,
});
const AccordionChevron = styled(ChevronDownIcon, {
transition: 'transform 300ms',
'[data-state=open] &': {
transform: 'rotate(180deg)',
},
});
export default () => (
<StyledAccordion type="single" defaultValue="item-1">
<StyledItem value="item-1">
<StyledHeader>
<StyledTrigger>
Item 1
<AccordionChevron aria-hidden />
</StyledTrigger>
</StyledHeader>
<StyledContent>
Here goes the content for the accordion item 1.
</StyledContent>
</StyledItem>
<StyledItem value="item-2">
<StyledHeader>
<StyledTrigger>
Item 2
<AccordionChevron aria-hidden />
</StyledTrigger>
</StyledHeader>
<StyledContent>
Here goes the content for the accordion item 2.
</StyledContent>
</StyledItem>
<StyledItem value="item-3">
<StyledHeader>
<StyledTrigger>
Item 3
<AccordionChevron aria-hidden />
</StyledTrigger>
</StyledHeader>
<StyledContent>
Here goes the content for the accordion item 3.
</StyledContent>
</StyledItem>
</StyledAccordion>
);

Here goes the content for the accordion item 2.

import { styled } from 'path-to/stitches.config';
import * as Accordion from '@radix-ui/react-accordion';
import { ChevronDownIcon } from '@radix-ui/react-icons';
// prettier-ignore
const StyledAccordion = styled(Accordion.Root, { /* styles */ });
const StyledItem = styled(Accordion.Item, {
// sry
});
const StyledHeader = styled(Accordion.Header, {
margin: 0,
display: 'flex',
});
const StyledTrigger = styled(Accordion.Trigger, {
backgroundColor: 'transparent',
border: 'none',
padding: 10,
flex: 1,
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
});
const StyledContent = styled(Accordion.Content, {
padding: 10,
});
const AccordionChevron = styled(ChevronDownIcon, {
transition: 'transform 300ms',
'[data-state=open] &': {
transform: 'rotate(180deg)',
},
});
export default () => (
<StyledAccordion type="single" defaultValue="item-2">
<StyledItem value="item-1">
<StyledHeader>
<StyledTrigger>
Item 1
<AccordionChevron aria-hidden />
</StyledTrigger>
</StyledHeader>
<StyledContent>
Here goes the content for the accordion item 1.
</StyledContent>
</StyledItem>
<StyledItem value="item-2">
<StyledHeader>
<StyledTrigger>
Item 2
<AccordionChevron aria-hidden />
</StyledTrigger>
</StyledHeader>
<StyledContent>
Here goes the content for the accordion item 2.
</StyledContent>
</StyledItem>
<StyledItem value="item-3">
<StyledHeader>
<StyledTrigger>
Item 3
<AccordionChevron aria-hidden />
</StyledTrigger>
</StyledHeader>
<StyledContent>
Here goes the content for the accordion item 3.
</StyledContent>
</StyledItem>
</StyledAccordion>
);

Here goes the content for the accordion item 1.

import { styled } from 'path-to/stitches.config';
import * as Accordion from '@radix-ui/react-accordion';
import { ChevronDownIcon } from '@radix-ui/react-icons';
const StyledAccordion = styled(Accordion.Root, {
borderTop: '1px solid gainsboro',
});
const StyledItem = styled(Accordion.Item, {
borderBottom: '1px solid gainsboro',
});
const StyledHeader = styled(Accordion.Header, {
margin: 0,
display: 'flex',
});
const StyledTrigger = styled(Accordion.Trigger, {
backgroundColor: 'transparent',
border: 'none',
padding: 10,
flex: 1,
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
});
const StyledContent = styled(Accordion.Content, {
padding: 10,
});
const AccordionChevron = styled(ChevronDownIcon, {
transition: 'transform 300ms',
'[data-state=open] &': {
transform: 'rotate(180deg)',
},
});
export default () => (
<StyledAccordion type="single" defaultValue="item-1" collapsible>
<StyledItem value="item-1">
<StyledHeader>
<StyledTrigger>
Item 1
<AccordionChevron aria-hidden />
</StyledTrigger>
</StyledHeader>
<StyledContent>
Here goes the content for the accordion item 1.
</StyledContent>
</StyledItem>
<StyledItem value="item-2">
<StyledHeader>
<StyledTrigger>
Item 2
<AccordionChevron aria-hidden />
</StyledTrigger>
</StyledHeader>
<StyledContent>
Here goes the content for the accordion item 2.
</StyledContent>
</StyledItem>
<StyledItem value="item-3">
<StyledHeader>
<StyledTrigger>
Item 3
<AccordionChevron aria-hidden />
</StyledTrigger>
</StyledHeader>
<StyledContent>
Here goes the content for the accordion item 3.
</StyledContent>
</StyledItem>
</StyledAccordion>
);

Here goes the content for the accordion item 2.

Here goes the content for the accordion item 3.
import { styled } from 'path-to/stitches.config';
import * as Accordion from '@radix-ui/react-accordion';
import { ChevronDownIcon } from '@radix-ui/react-icons';
const StyledAccordion = styled(Accordion.Root, {
borderTop: '1px solid gainsboro',
});
const StyledItem = styled(Accordion.Item, {
borderBottom: '1px solid gainsboro',
});
const StyledHeader = styled(Accordion.Header, {
margin: 0,
display: 'flex',
});
const StyledTrigger = styled(Accordion.Trigger, {
backgroundColor: 'transparent',
border: 'none',
padding: 10,
flex: 1,
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
});
const StyledContent = styled(Accordion.Content, {
padding: 10,
});
const AccordionChevron = styled(ChevronDownIcon, {
transition: 'transform 300ms',
'[data-state=open] &': {
transform: 'rotate(180deg)',
},
});
export default () => (
<StyledAccordion type="multiple" defaultValue={['item-2', 'item-3']} >
<StyledItem value="item-1">
<StyledHeader>
<StyledTrigger>
Item 1
<AccordionChevron aria-hidden />
</StyledTrigger>
</StyledHeader>
<StyledContent>
Here goes the content for the accordion item 1.
</StyledContent>
</StyledItem>
<StyledItem value="item-2">
<StyledHeader>
<StyledTrigger>
Item 2
<AccordionChevron aria-hidden />
</StyledTrigger>
</StyledHeader>
<StyledContent>
Here goes the content for the accordion item 2.
</StyledContent>
</StyledItem>
<StyledItem value="item-3">
<StyledHeader>
<StyledTrigger>
Item 3
<AccordionChevron aria-hidden />
</StyledTrigger>
</StyledHeader>
<StyledContent>
Here goes the content for the accordion item 3.
</StyledContent>
</StyledItem>
</StyledAccordion>
);

Adheres to the Accordion WAI-ARIA design pattern.

KeyDescription
SpaceWhen focus is on an Accordion.Trigger of a collapsed section, expands the section.
EnterWhen focus is on an Accordion.Trigger of a collapsed section, expands the section.
TabMoves focus to the next focusable element.
Shift + TabMoves focus to the previous focusable element.
ArrowDownMoves focus to the next Accordion.Trigger.
ArrowUpMoves focus to the previous Accordion.Trigger.
HomeWhen focus is on an Accordion.Trigger, moves focus to the first Accordion.Trigger.
EndWhen focus is on an Accordion.Trigger, moves focus to the last Accordion.Trigger.