4
votes

Using the docs/examples for overriding Material UI styling with styled-components, I've managed to style the root and "deeper elements" within an ExpansionPanel and ExpansionPanelDetails.

However, when I use the same technique to return an overridden ExpansionPanelSummary from a function passed to styled(), the ExpansionPanelSummary moves in the DOM and the whole ExpansionPanel no longer renders correctly.

The technique in question, as applied to ExpansionPanel (this works as expected, on the container ExpansionPanel):

import MUIExpansionPanel from '@material-ui/core/ExpansionPanel';

export const ExpansionPanel = styled(props => (
  <MUIExpansionPanel
    classes={{expanded: 'expanded'}}
    {...props}
  />
))`
  && {
    ...root style overrides
  }
  &&.expanded {
    ...expanded style overrides
  }
`;

The typical DOM (with class names abbreviated) for ExpansionPanel and friends:

<div class="MuiExpansionPanel...">
  <div class="MuiExpansionPanelSummary..." />
  <div class="MuiCollapse-container...>
    <div class="MuiCollapse-wrapper...>
      <div class="MuiCollapse-wrapperInner...>
        <div class="MuiExpansionPanelDetails..." />
      </div>
    </div>
  </div>
</div>

The DOM when I apply the above technique to ExpansionPanelSummary:

<div class="MuiExpansionPanel...">
  <div class="MuiCollapse-container...>
    <div class="MuiCollapse-wrapper...>
      <div class="MuiCollapse-wrapperInner...>
        <div class="MuiExpansionPanelSummary..." />
        <div class="MuiExpansionPanelDetails..." />
      </div>
    </div>
  </div>
</div>

For completeness, here's a minimal repro of what I'm doing to ExpansionPanelSummary, that triggers the DOM switch:

export const ExpansionPanelSummary = styled(props => (
  <MUIExpansionPanelSummary
    {...props}
  />
))``;

And my JSX is standard ExpansionPanel setup:

<ExpansionPanel>
  <ExpansionPanelSummary>
    Summary Label
  </ExpansionPanelSummary>
  <ExpansionPanelDetails>
    <div>Some Content</div>
  </ExpansionPanelDetails>
</ExpansionPanel>
1

1 Answers

2
votes

This difficulty is independent of using styled-components and just has to do with wrapping ExpansionPanelSummary in another component.

You can similarly reproduce this with the following wrapping of ExpansionPanelSummary:

const MyCustomSummary = props => {
  return (
    <ExpansionPanelSummary {...props} expandIcon={<ExpandMoreIcon />}>
      <Typography>{props.text}</Typography>
    </ExpansionPanelSummary>
  );
};

There are several component groups like this where a Material-UI parent component looks for a particular type of child component and treats that child specially. For instance, you can find the following block in ExpansionPanel

      if (isMuiElement(child, ['ExpansionPanelSummary'])) {
        summary = React.cloneElement(child, {
          disabled,
          expanded,
          onChange: this.handleChange,
        });
        return null;
      }

Fortunately, Material-UI has a straightforward way to tell it that your custom component should be treated the same as a particular Material-UI component via the muiName property:

MyCustomSummary.muiName = "ExpansionPanelSummary";

or in your case it would look like:

export const ExpansionPanelSummary = styled(props => (
  <MUIExpansionPanelSummary
    {...props}
  />
))``;

ExpansionPanelSummary.muiName = "ExpansionPanelSummary";

Edit Custom ExpansionPanelSummary