The Ultimate Guide to Styling and Customizing the MUI Accordion

The Material-UI Accordion (previously known as the expansion panel) is commonly used for controlling when secondary components or information is displayed.

In this example, we will build an Accordion that has components nested in both the summary and details sections and discuss the different components that compose an Accordion (AccordionSummary, AccordionActions, AccordionDetails).

We will also add common stylings to the Accordion (width, height, border, etc).

Accordion with background color, elevation, and a custom icon
Accordion with background color, elevation, and a custom icon

I moved MUI Accordion onclick and expansion into a separate post for easier reading, but it builds off of this tutorial. I also upgraded the code to MUI v5 in the onClick/expansion post and use the new sx prop.

Code Sandbox with full React code is in the Resources section.

The Material-UI Accordion is really a wrapper around nested helper components. Not all nested components are required with every accordion. Below is a list of the components and their functions:

  • Accordion – This component wraps the helper components and controls props such as defaultExpanded and a couple of props related to the expansion animation.
  • AccordionSummary – This component is required for expansion functionality on clicks (but not required for rendering). It also contains the expandIcon.
  • AccordionDetails – This component is optional for full functionality. However, it comes with default styling that you most likely want, so I recommend using it.
  • AccordionActions – This is an optional wrapper used to contain action buttons/icons/etc. It comes with a useful spacing prop for default spacing of action components.

Accordion, AccordionSummary, AccordionDetails, and AccordionActions JSX Example

The JSX for this example is quite verbose, partially due to extra divs for aligning the sliders just right. My example is a fork of this example from the docs.

<div className={classes.root}>
  {/*elevation is  not listed in docs but is available*/}
  <Accordion 
    defaultExpanded 
    elevation={3} 
    className={classes.accordion}
  >
    <AccordionSummary
      expandIcon={expanded ? <RemoveIcon /> : <AddIcon />}
      onClick={() => {
        setExpanded(!expanded);
      }}
    >
      <div className={classes.column}>
        <Typography 
          className={classes.heading}
        >
          Settings
        </Typography>
      </div>
      <div className={classes.column}>
        <Typography className={classes.secondaryHeading}>
          Primary Setting
        </Typography>
        <FormControlLabel
          style={{ width: "100%" }}
          aria-label="Acknowledge"
          onClick={(event) => event.stopPropagation()}
          onFocus={(event) => event.stopPropagation()}
          control={
            <Slider 
              value={primaryValue}
              onChange={handlePrimaryChange} 
            />
          }
        />
      </div>
    </AccordionSummary>
    <AccordionDetails className={classes.details}>
      <div className={classes.column} />
      <div className={classes.column}>
        <Typography className={classes.secondaryHeading}>
          Secondary Setting
        </Typography>
        <FormControlLabel
          style={{ width: "100%" }}
          aria-label="Acknowledge"
          onClick={(event) => event.stopPropagation()}
          onFocus={(event) => event.stopPropagation()}
          control={
            <Slider
              value={secondaryValue}
              onChange={handleSecondaryChange}
            />
          }
        />
      </div>
      <div className={clsx(classes.column, classes.helper)}></div>
    </AccordionDetails>
    <AccordionActions>
      <Button size="small">Cancel</Button>
      <Button
        size="small"
        onClick={() => {
          setPrimaryValue(0);
          setSecondaryValue(0);
        }}
      >
        Reset
      </Button>
      <Button size="small">Save</Button>
    </AccordionActions>
  </Accordion>
</div>

Notice that even though elevation isn’t mentioned in the docs, it is an accepted prop on the Accordion. This is because Paper is actually the root element of the Accordion, per the API docs. Adding elevation is a shorthand for adding shadow styling to the Accordion. Shadow can also be accomplished by directly applying box-shadow styling via css.

Notice how I’ve used all the subcomponents discussed above to contain sliders, text, and action buttons. I’ve also used added a state management Boolean (expanded) to track expansion state. Normally this isn’t needed. However, I wanted to swap out the open/close icon depending on state. I also had to disable the default transition applied to the expandIcon, and I’ll discuss this shortly in the styling section below.

Finally, when the Slider components are clicked, we have to stop that click event from propagating and accidentally contracting the Accordion. This is accomplished with the FormControlLabel‘s onClick={(event) => event.stopPropagation()} (the MUI docs did a good job of demonstrating this).

MUI Accordion Width, Height, and Border

The code below applies classes to three different components in order to achieve the desired styling:

  • root is applied to the wrapping div to control width
  • accordion is applied to the Accordion component to control height
  • details is applied to AccordionDetails. This is only visible on expansion.
root: {
  width: "100%"
},
accordion: {
    minHeight: 150, //ugly but works
    height: "100%"
},
details: {
  alignItems: "center",
  border: "1px solid rgba(0,0,0,0.1)",
  borderRadius: 4
}

Here’s a detailed description of each styling:

  • Accordion width: this is easy to customize. Simply target the wrapping div.
  • Background color: I left background color unchanged when the Accordion is closed. I added background to the wrapping div and this colored the whole component. Alternatively I could have targeted the Accordion component.
  • Height: I don’t recommend changing height. I did in my demo just to show that it is possible. If you want to do it, add a minimum height and then leave the height attribute at 100%. The minimum height will only affect the Accordion when it is closed, as long as the minimum is less than the total natural vertical size when expanded. However, it’s best to simply let the Accordion take its vertical size based on its internal components.

Material-UI Accordion Vs Expansion Panel

You may have used or encountered the Expansion Panel component previously. What’s the difference between the Expansion Panel component and the Accordion? Nothing but the name.

Per Material-UI Docs

The ExpansionPanel component was renamed to Accordion to use a more common naming convention.

You should use import { Accordion } from '@material-ui/core' or import Accordion from '@material-ui/core/Accordion'.

Source: MUI ExpansionPanel Docs

Resources

Think you’re a JavaScript expert? Test yourself on these 50 difficult JavaScript questions.

Here’s how to add custom icons to Bootstrap’s Accordion.

Code Sandbox Link

Share this post:

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.