Accordion
The Accordion component lets users show and hide sections of related content on a page.
Introduction
- Accordion: the wrapper for grouping related components.
- Accordion Summary: the wrapper for the Accordion header, which expands or collapses the content when clicked.
- Accordion Details: the wrapper for the Accordion content.
- Accordion Actions: an optional wrapper that groups a set of buttons.
Accordion 1
Accordion 2
import * as React from 'react'; import Accordion from '@mui/material/Accordion'; import AccordionActions from '@mui/material/AccordionActions'; import AccordionSummary from '@mui/material/AccordionSummary'; import AccordionDetails from '@mui/material/AccordionDetails'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import Button from '@mui/material/Button'; export default function AccordionUsage() { return ( <div> <Accordion> <AccordionSummary expandIcon={<ExpandMoreIcon />} aria-controls="panel1-content" id="panel1-header" > Accordion 1 </AccordionSummary> <AccordionDetails> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget. </AccordionDetails> </Accordion> <Accordion> <AccordionSummary expandIcon={<ExpandMoreIcon />} aria-controls="panel2-content" id="panel2-header" > Accordion 2 </AccordionSummary> <AccordionDetails> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget. </AccordionDetails> </Accordion> <Accordion defaultExpanded> <AccordionSummary expandIcon={<ExpandMoreIcon />} aria-controls="panel3-content" id="panel3-header" > Accordion Actions </AccordionSummary> <AccordionDetails> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget. </AccordionDetails> <AccordionActions> <Button>Cancel</Button> <Button>Agree</Button> </AccordionActions> </Accordion> </div> ); }
Basics
import Accordion from '@mui/material/Accordion'; import AccordionDetails from '@mui/material/AccordionDetails'; import AccordionSummary from '@mui/material/AccordionSummary';
Expand icon
expandIcon
prop on the Accordion Summary component to change the expand indicator icon. The component handles the turning upside-down transition automatically.Accordion 1
Accordion 1
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget.
Accordion 2
Accordion 2
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget.
import * as React from 'react'; import Accordion from '@mui/material/Accordion'; import AccordionSummary from '@mui/material/AccordionSummary'; import AccordionDetails from '@mui/material/AccordionDetails'; import Typography from '@mui/material/Typography'; import ArrowDownwardIcon from '@mui/icons-material/ArrowDownward'; import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown'; export default function AccordionExpandIcon() { return ( <div> <Accordion> <AccordionSummary expandIcon={<ArrowDownwardIcon />} aria-controls="panel1-content" id="panel1-header" > <Typography>Accordion 1</Typography> </AccordionSummary> <AccordionDetails> <Typography> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget. </Typography> </AccordionDetails> </Accordion> <Accordion> <AccordionSummary expandIcon={<ArrowDropDownIcon />} aria-controls="panel2-content" id="panel2-header" > <Typography>Accordion 2</Typography> </AccordionSummary> <AccordionDetails> <Typography> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget. </Typography> </AccordionDetails> </Accordion> </div> ); }
Expanded by default
defaultExpanded
prop on the Accordion component to have it opened by default.Header
Header
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget.
import * as React from 'react'; import Accordion from '@mui/material/Accordion'; import AccordionSummary from '@mui/material/AccordionSummary'; import AccordionDetails from '@mui/material/AccordionDetails'; import Typography from '@mui/material/Typography'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; export default function AccordionExpandDefault() { return ( <div> <Accordion defaultExpanded> <AccordionSummary expandIcon={<ExpandMoreIcon />} aria-controls="panel1-content" id="panel1-header" > <Typography>Expanded by default</Typography> </AccordionSummary> <AccordionDetails> <Typography> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget. </Typography> </AccordionDetails> </Accordion> <Accordion> <AccordionSummary expandIcon={<ExpandMoreIcon />} aria-controls="panel2-content" id="panel2-header" > <Typography>Header</Typography> </AccordionSummary> <AccordionDetails> <Typography> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget. </Typography> </AccordionDetails> </Accordion> </div> ); }
Transition
slots.transition
and slotProps.transition
props to change the Accordion's default transition.Custom transition using Fade
Custom transition using Fade
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget.
Default transition using Collapse
Default transition using Collapse
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget.
import * as React from 'react'; import Accordion, { AccordionSlots, accordionClasses, } from '@mui/material/Accordion'; import AccordionSummary from '@mui/material/AccordionSummary'; import AccordionDetails, { accordionDetailsClasses, } from '@mui/material/AccordionDetails'; import Typography from '@mui/material/Typography'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import Fade from '@mui/material/Fade'; export default function AccordionTransition() { const [expanded, setExpanded] = React.useState(false); const handleExpansion = () => { setExpanded((prevExpanded) => !prevExpanded); }; return ( <div> <Accordion expanded={expanded} onChange={handleExpansion} slots={{ transition: Fade as AccordionSlots['transition'] }} slotProps={{ transition: { timeout: 400 } }} sx={[ expanded ? { [`& .${accordionClasses.region}`]: { height: 'auto', }, [`& .${accordionDetailsClasses.root}`]: { display: 'block', }, } : { [`& .${accordionClasses.region}`]: { height: 0, }, [`& .${accordionDetailsClasses.root}`]: { display: 'none', }, }, ]} > <AccordionSummary expandIcon={<ExpandMoreIcon />} aria-controls="panel1-content" id="panel1-header" > <Typography>Custom transition using Fade</Typography> </AccordionSummary> <AccordionDetails> <Typography> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget. </Typography> </AccordionDetails> </Accordion> <Accordion> <AccordionSummary expandIcon={<ExpandMoreIcon />} aria-controls="panel2-content" id="panel2-header" > <Typography>Default transition using Collapse</Typography> </AccordionSummary> <AccordionDetails> <Typography> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget. </Typography> </AccordionDetails> </Accordion> </div> ); }
Disabled item
disabled
prop on the Accordion component to disable interaction and focus.Accordion 1
Accordion 1
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget.
Accordion 2
Accordion 2
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget.
Disabled Accordion
Disabled Accordion
import * as React from 'react'; import Accordion from '@mui/material/Accordion'; import AccordionSummary from '@mui/material/AccordionSummary'; import AccordionDetails from '@mui/material/AccordionDetails'; import Typography from '@mui/material/Typography'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; export default function DisabledAccordion() { return ( <div> <Accordion> <AccordionSummary expandIcon={<ExpandMoreIcon />} aria-controls="panel1-content" id="panel1-header" > <Typography>Accordion 1</Typography> </AccordionSummary> <AccordionDetails> <Typography> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget. </Typography> </AccordionDetails> </Accordion> <Accordion> <AccordionSummary expandIcon={<ExpandMoreIcon />} aria-controls="panel2-content" id="panel2-header" > <Typography>Accordion 2</Typography> </AccordionSummary> <AccordionDetails> <Typography> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget. </Typography> </AccordionDetails> </Accordion> <Accordion disabled> <AccordionSummary expandIcon={<ExpandMoreIcon />} aria-controls="panel3-content" id="panel3-header" > <Typography>Disabled Accordion</Typography> </AccordionSummary> </Accordion> </div> ); }
Controlled Accordion
General settings
I am an accordion
General settings
I am an accordion
Nulla facilisi. Phasellus sollicitudin nulla et quam mattis feugiat. Aliquam eget maximus est, id dignissim quam.
Users
You are currently not an owner
Users
You are currently not an owner
Donec placerat, lectus sed mattis semper, neque lectus feugiat lectus, varius pulvinar diam eros in elit. Pellentesque convallis laoreet laoreet.
Advanced settings
Filtering has been entirely disabled for whole web server
Advanced settings
Filtering has been entirely disabled for whole web server
Nunc vitae orci ultricies, auctor nunc in, volutpat nisl. Integer sit amet egestas eros, vitae egestas augue. Duis vel est augue.
Personal data
Personal data
Nunc vitae orci ultricies, auctor nunc in, volutpat nisl. Integer sit amet egestas eros, vitae egestas augue. Duis vel est augue.
import * as React from 'react'; import Accordion from '@mui/material/Accordion'; import AccordionDetails from '@mui/material/AccordionDetails'; import AccordionSummary from '@mui/material/AccordionSummary'; import Typography from '@mui/material/Typography'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; export default function ControlledAccordions() { const [expanded, setExpanded] = React.useState<string | false>(false); const handleChange = (panel: string) => (event: React.SyntheticEvent, isExpanded: boolean) => { setExpanded(isExpanded ? panel : false); }; return ( <div> <Accordion expanded={expanded === 'panel1'} onChange={handleChange('panel1')}> <AccordionSummary expandIcon={<ExpandMoreIcon />} aria-controls="panel1bh-content" id="panel1bh-header" > <Typography sx={{ width: '33%', flexShrink: 0 }}> General settings </Typography> <Typography sx={{ color: 'text.secondary' }}>I am an accordion</Typography> </AccordionSummary> <AccordionDetails> <Typography> Nulla facilisi. Phasellus sollicitudin nulla et quam mattis feugiat. Aliquam eget maximus est, id dignissim quam. </Typography> </AccordionDetails> </Accordion> <Accordion expanded={expanded === 'panel2'} onChange={handleChange('panel2')}> <AccordionSummary expandIcon={<ExpandMoreIcon />} aria-controls="panel2bh-content" id="panel2bh-header" > <Typography sx={{ width: '33%', flexShrink: 0 }}>Users</Typography> <Typography sx={{ color: 'text.secondary' }}> You are currently not an owner </Typography> </AccordionSummary> <AccordionDetails> <Typography> Donec placerat, lectus sed mattis semper, neque lectus feugiat lectus, varius pulvinar diam eros in elit. Pellentesque convallis laoreet laoreet. </Typography> </AccordionDetails> </Accordion> <Accordion expanded={expanded === 'panel3'} onChange={handleChange('panel3')}> <AccordionSummary expandIcon={<ExpandMoreIcon />} aria-controls="panel3bh-content" id="panel3bh-header" > <Typography sx={{ width: '33%', flexShrink: 0 }}> Advanced settings </Typography> <Typography sx={{ color: 'text.secondary' }}> Filtering has been entirely disabled for whole web server </Typography> </AccordionSummary> <AccordionDetails> <Typography> Nunc vitae orci ultricies, auctor nunc in, volutpat nisl. Integer sit amet egestas eros, vitae egestas augue. Duis vel est augue. </Typography> </AccordionDetails> </Accordion> <Accordion expanded={expanded === 'panel4'} onChange={handleChange('panel4')}> <AccordionSummary expandIcon={<ExpandMoreIcon />} aria-controls="panel4bh-content" id="panel4bh-header" > <Typography sx={{ width: '33%', flexShrink: 0 }}>Personal data</Typography> </AccordionSummary> <AccordionDetails> <Typography> Nunc vitae orci ultricies, auctor nunc in, volutpat nisl. Integer sit amet egestas eros, vitae egestas augue. Duis vel est augue. </Typography> </AccordionDetails> </Accordion> </div> ); }
- A component is controlled when it's managed by its parent using props.
- A component is uncontrolled when it's managed by its own local state.
Customization
Only one expanded at a time
expanded
prop with React's useState
hook to allow only one Accordion item to be expanded at a time. The demo below also shows a bit of visual customization.Collapsible Group Item #2
Collapsible Group Item #2
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget.
Collapsible Group Item #3
Collapsible Group Item #3
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget.
import * as React from 'react'; import { styled } from '@mui/material/styles'; import ArrowForwardIosSharpIcon from '@mui/icons-material/ArrowForwardIosSharp'; import MuiAccordion, { AccordionProps } from '@mui/material/Accordion'; import MuiAccordionSummary, { AccordionSummaryProps, accordionSummaryClasses, } from '@mui/material/AccordionSummary'; import MuiAccordionDetails from '@mui/material/AccordionDetails'; import Typography from '@mui/material/Typography'; const Accordion = styled((props: AccordionProps) => ( <MuiAccordion disableGutters elevation={0} square {...props} /> ))(({ theme }) => ({ border: `1px solid ${theme.palette.divider}`, '&:not(:last-child)': { borderBottom: 0, }, '&::before': { display: 'none', }, })); const AccordionSummary = styled((props: AccordionSummaryProps) => ( <MuiAccordionSummary expandIcon={<ArrowForwardIosSharpIcon sx={{ fontSize: '0.9rem' }} />} {...props} /> ))(({ theme }) => ({ backgroundColor: 'rgba(0, 0, 0, .03)', flexDirection: 'row-reverse', [`& .${accordionSummaryClasses.expandIconWrapper}.${accordionSummaryClasses.expanded}`]: { transform: 'rotate(90deg)', }, [`& .${accordionSummaryClasses.content}`]: { marginLeft: theme.spacing(1), }, ...theme.applyStyles('dark', { backgroundColor: 'rgba(255, 255, 255, .05)', }), })); const AccordionDetails = styled(MuiAccordionDetails)(({ theme }) => ({ padding: theme.spacing(2), borderTop: '1px solid rgba(0, 0, 0, .125)', })); export default function CustomizedAccordions() { const [expanded, setExpanded] = React.useState<string | false>('panel1'); const handleChange = (panel: string) => (event: React.SyntheticEvent, newExpanded: boolean) => { setExpanded(newExpanded ? panel : false); }; return ( <div> <Accordion expanded={expanded === 'panel1'} onChange={handleChange('panel1')}> <AccordionSummary aria-controls="panel1d-content" id="panel1d-header"> <Typography>Collapsible Group Item #1</Typography> </AccordionSummary> <AccordionDetails> <Typography> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget. </Typography> </AccordionDetails> </Accordion> <Accordion expanded={expanded === 'panel2'} onChange={handleChange('panel2')}> <AccordionSummary aria-controls="panel2d-content" id="panel2d-header"> <Typography>Collapsible Group Item #2</Typography> </AccordionSummary> <AccordionDetails> <Typography> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget. </Typography> </AccordionDetails> </Accordion> <Accordion expanded={expanded === 'panel3'} onChange={handleChange('panel3')}> <AccordionSummary aria-controls="panel3d-content" id="panel3d-header"> <Typography>Collapsible Group Item #3</Typography> </AccordionSummary> <AccordionDetails> <Typography> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget. </Typography> </AccordionDetails> </Accordion> </div> ); }
Changing heading level
h3
element for the heading. You can change the heading element using the slotProps.heading.component
prop to ensure the correct heading hierarchy in your document.<Accordion slotProps={{ heading: { component: 'h4' } }}> <AccordionSummary expandIcon={<ExpandMoreIcon />} aria-controls="panel1-content" id="panel1-header" > Accordion </AccordionSummary> <AccordionDetails> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget. </AccordionDetails> </Accordion>
Performance
unmountOnExit
to true
inside the slotProps.transition
prop to improve performance:<Accordion slotProps={{ transition: { unmountOnExit: true } }} />
Accessibility
id
and aria-controls
, which in this case would apply to the Accordion Summary component. The Accordion component then derives the necessary aria-labelledby
and id
from its content.<Accordion> <AccordionSummary id="panel-header" aria-controls="panel-content"> Header </AccordionSummary> <AccordionDetails> Lorem ipsum dolor sit amet, consectetur adipiscing elit. </AccordionDetails> </Accordion>
Anatomy
<div>
that houses interior elements like the Accordion Summary and other optional components (such as buttons or decorators).<div className="MuiAccordion-root"> <div className="MuiButtonBase-root MuiAccordionSummary-root" role="button" aria-expanded=""> </div> <div className="MuiAccordion-region" role="region"> <div className="MuiAccordionDetails-root"> </div> </div> </div>