Search code examples
reactjsmaterial-uistyled-componentsreact-props

React Material UI v5 styled with defaultProps


When using multiple styled components, the top one overrides other default props.

import { styled } from '@mui/material/styles'
import { Badge } from '@mui/material'


const Badge1 = styled(Badge)``

// this works if Badge1 is used directly: <Badge1 />
Badge1.defaultProps = {
    max: Infinity
}


const Badge2 = styled(Badge1)``    // styled Badge1

// this overrides defaultProps from Badge1. Prop max: Infinity does no apply here
Badge2.defaultProps = {
    variant: 'standard'
}

Badge2 has only variant: 'standard' default prop. It skips max: Infinity

How can I keep all the defaultProps from each level


Solution

  • When you style a component via multiple styled calls using Emotion, Emotion collapses the styling layers into a single wrapper component rather than adding an additional wrapper around the first wrapper. Emotion retains the defaultProps from the previous wrapper, but you are then overwriting that when you set Badge2.defaultProps.

    You can retain any previous defaultProps with the following syntax:

    Badge2.defaultProps = {
        ...Badge2.defaultProps,
        variant: 'standard'
    }
    

    Below is an example demonstrating what happens with default props with each styled wrapping. The fix is demonstrated with StyledAgainWithDefaultRetainExisting.

    import styled from "@emotion/styled";
    
    function MyComponent({ className, ...defaults }) {
      return <div className={className}>Defaults: {JSON.stringify(defaults)}</div>;
    }
    MyComponent.defaultProps = {
      orig: true
    };
    
    const StyledMyComponent = styled(MyComponent)`
      background-color: blue;
      color: white;
    `;
    StyledMyComponent.defaultProps = {
      styled: true
    };
    
    const StyledAgainNoDefaultsAdded = styled(StyledMyComponent)`
      background-color: purple;
    `;
    
    const StyledAgainWithDefault = styled(StyledMyComponent)`
      background-color: green;
    `;
    StyledAgainWithDefault.defaultProps = {
      styledAgain: true
    };
    
    const StyledAgainWithDefaultRetainExisting = styled(StyledMyComponent)`
      background-color: brown;
    `;
    StyledAgainWithDefaultRetainExisting.defaultProps = {
      ...StyledAgainWithDefaultRetainExisting.defaultProps,
      styledAgainRetain: true
    };
    
    export default function App() {
      return (
        <div>
          <MyComponent />
          <StyledMyComponent />
          <StyledAgainNoDefaultsAdded />
          <StyledAgainWithDefault />
          <StyledAgainWithDefaultRetainExisting />
        </div>
      );
    }
    

    Edit styled and defaultProps