Styled Components in Material UI (MUI) with Styled Utility
Tags: react, materialui, styledcomponent, webdev
Published: 2022-08-01 12:20:00


If you are already familiar with styled components, you might want to use that along with the MUI. To use styled-component with MUI, there is `styled()` utility.  The [official documentation](https://mui.com/system/styled/) of MUI doesn't have enough examples with the styled() utility. This article's purpose is to provide enough examples of styled() utility with both `Javascript object syntax` & `CSS like syntax`. 


&nbsp;

**📑Table of Contents**

- [Basic](#basic)
- [MUI Theme in the styled() Utility](#mui-theme-in-the-styled-utility)
- [Media Queries](#media-queries)
- [Child Component and Child Element](#child-component-and-child-element)
- [Pseudo Classes](#pseudo-classes)
- [Sibling Component](#sibling-component)
- [Props](#props)
- [sx Prop can be used as an Alternative to the styled Utility](#sx-prop-can-be-used-as-an-alternative-to-the-styled-utility)


&nbsp;
## Basic
&nbsp;


**Import**
&nbsp;

```js
// You must import 'styled' utility form mui
import { styled } from '@mui/material/styles';

// Also, you must import the components which you are gonna use with the styled utility
import Box from '@mui/material/Box';
```



&nbsp;

**JavaScript Object Syntax**

&nbsp;


Let's create a component with `styled()` utility by using JavaScript object syntax:

```js
const Basic = styled(Box)({

  backgroundColor: 'aliceblue',
  color: 'darkslategray',
  padding: '2rem',
  textAlign:'center'
  
})
```

>Note:
> - Here, we are using the `Box` component but instead of the `Box` component, we can use any other MUI component. We just need to import that component. 
> - Instead of a component we can also use an HTML tag. To use HTML tag, we have to put the HTML tag inside quote, `styled('div')`. 
> - Here, the variable name is `Basic`. Always make sure that the first letter of the variable is capital because it will work like a component and a component name has to start with a capital letter. 


&nbsp;

**CSS Like Syntax**

&nbsp;


Instead of JavaScript object syntax, we can also have CSS-like syntax: 

```js
const Basic = styled(Box)`
  background-color: aliceblue;
  color: darkslategray;
  padding: 2rem;
  text-align: center;
`;
```


> Note:
>
> - Don't forget the `backticks`
>
> - Semicolon after ending backtick is optional.




&nbsp;

## MUI Theme in the styled() Utility

&nbsp;


Take a look at the [default theme](https://mui.com/material-ui/customization/default-theme/) of MUI.


&nbsp;

**JavaScript Object Syntax**

&nbsp;


```js
const UsingTheme = styled(Box)(
  ({ theme }) => ({
    backgroundColor: theme.palette.primary.light,
    color: theme.palette.grey[900],
    padding: theme.spacing(2),
    textAlign: 'center',
    ...theme.typography.h6,
  })
)

```

The following picture is showing the MUI default theme. In the picture, we can see that the `h6` is an object. It has `fontFamily`, `fontWeight`, `fontSize`, `lineHeight` & `letterSpacing` properties. We want all of them. So, we are destructuring it (`...theme.typography.h6,`).

<img src='https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gqofsgih7f2vr308yn2x.png' alt="mui theme" width="400"/>


 

&nbsp;

**CSS Like Syntax**

&nbsp;


```js
const UsingTheme = styled(Box)(
  ({ theme }) => `
  background-color: ${theme.palette.primary.light};
  color: ${theme.palette.grey[900]};
  padding: ${theme.spacing(2)};
  text-align: center;


  ${ /* here, we can't destructure like javascript object syntax. So, we need to manually access all the properties of 'h6'  */'' }

  font-size: ${theme.typography.h6.fontSize};
  font-weight: ${theme.typography.h6.fontWeight};
  font-family: ${theme.typography.h6.fontFamily};
  line-height: ${theme.typography.h6.lineHeight};
  letter-spacing: ${theme.typography.h6.letterSpacing};
 `,
)

```


&nbsp;

![rich-text-editor-for-react npm package](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/scz09ynfwbdvqflj9ssh.png)
>[Demo](https://rich-text-editor-for-react.rasaf-ibrahim.com) | [Documentation](https://docs.rich-text-editor-for-react.rasaf-ibrahim.com)




&nbsp;

## Media Queries



&nbsp;

**JavaScript Object Syntax**

&nbsp;


Let's see an example of using media queries with JavaScript Object Syntax:

```js
const UsingMediaQuery = styled(Box)(
    ({ theme }) => ({

      backgroundColor: theme.palette.primary.light,
      color: theme.palette.grey[900],
  
      "@media (min-width:640px)": {
            
          backgroundColor: theme.palette.primary.dark,
          color: theme.palette.grey[100],
       },
  

       /* here, we are accessing breakpoints' value from the theme */

       [`@media screen and (min-width: ${theme.breakpoints.values.md}px)`]: {
         
         backgroundColor: theme.palette.secondary.light,
         color: theme.palette.grey[900],
      },
      
    })
  )

```



&nbsp;

**CSS Like Syntax**

&nbsp;




```js

const UsingMediaQuery = styled(Box)(

    ({ theme }) => `

    background-color: ${theme.palette.primary.light};
    color: ${theme.palette.grey[900]};


    @media (min-width: 640px) {

        background-color: ${theme.palette.primary.dark};
        color: ${theme.palette.grey[100]};
    }

    
   ${ /* here, we are accessing breakpoints' value from the theme */'' }

    @media (min-width: ${theme.breakpoints.values.md}px) {

        background-color: ${theme.palette.secondary.light};
        color: ${theme.palette.grey[900]};
    }

   `,
  )
  
```



&nbsp;

**We can't have same media query more than one time in `JavaScript Object Syntax`**

&nbsp;


Suppose, there is class a `box-section` in the html and we are styling it by writing normal CSS:

```css

@media (min-width: 640px) {

  .box-section {

      margin: 1rem;

  }

}


@media (min-width: 640px) {

  .box-section {

      padding: 1rem;

  }

}

```

In the above example, we can see that the both media query is actually same. So, it was enough to have one media query and all the properties inside it. But we have written the same media query twice.  Writing same media query twice like the above example has no problem, the code will work perfectly.


But when we write the same media query multiple times while working with styled component's JavaScript Syntax, only the last media query's code will be executed:


```js
const Box_Section = styled(Box)(
    ({ theme }) => ({
  
      "@media (min-width:640px)": {
            
            margin:'1rem'
          
       },

       "@media (min-width:640px)": {
            
            padding:'1rem'
          
       },


    )}

  ) 
```


In the above example, as the both media query is same, only the last media query's code will be executed. So, the `Box_Section` component will only have `padding`, not `margin`. 

&nbsp;
> Reason of this problem:
As we are working with JavaScript object here, we must have unique property name. But in the above example, we are having `"@media (min-width:640px)"` property name twice. So, JavaScript is considering the last property name's value to be the updated version and only having that.



&nbsp;
>Note: This problem will not occur with `CSS Like Syntax` in styled components. We can have same media query more than one time just like normal CSS.  










&nbsp;

## Child Component and Child Element

&nbsp;



**JSX**

&nbsp;

Suppose, we want the following `JSX`: 


```jsx
<ParentComponent>
        
      <div>Hi</div>

     <Box className='childComponent'> Hello </Box>

</ParentComponent>

```
So, we need to create the `ParentComponent` component and also need to style the child element `div` and child component `Box`.


&nbsp;

**JavaScript Object Syntax**

&nbsp;


```js

const ParentComponent = styled(Box)(

  ({ theme }) => ({

    backgroundColor: theme.palette.primary.light,
    color: theme.palette.grey[900],
    padding: theme.spacing(2),
    textAlign: 'center',


    // Child element
    "> div": {
      backgroundColor: theme.palette.error.dark,
      color: theme.palette.grey[100]
    },


    // Child Component (We need to select the class or id which is used in the child component)
    "> .childComponent": {
      backgroundColor: theme.palette.success.dark,
      color: theme.palette.grey[100]
    },

  })
)

```

> Note:
>
> - I haven't found a way to select an MUI component without the class or an id that is used in that child component. If you know any way other, please write it down in the comment section. 




&nbsp;

**CSS Like Syntax**

&nbsp;


```js
const ParentComponent = styled(Box)(
  ({ theme }) => `
  background-color: ${theme.palette.primary.light};
  color: ${theme.palette.grey[900]};
  padding: ${theme.spacing(2)};
  text-align: center;


  ${ /* Child element  */'' }

  > div  {
    background-color: ${theme.palette.error.dark};
    color: ${theme.palette.grey[100]};
  };


  ${ /* Child Component (We need to select the class or id which is used in the child component)  */'' }

   > .childComponent {
    background-color: ${theme.palette.success.dark};
    color: ${theme.palette.grey[100]};
  };


 `,
)

```






&nbsp;

## Pseudo Classes

&nbsp;




**JSX**

&nbsp;

Suppose, we want the following `JSX`: 


```jsx
<PseudoClasses>
        
      <div>Hi</div>

     <Box className='childComponent'> Hello </Box>

</PseudoClasses>
```

So, we need to create the `PseudoClasses` component and also need to style the child element `div` and child component `Box` with pseudo-classes.



&nbsp;

**JavaScript Object Syntax**

&nbsp;


```js
const PseudoClasses = styled(Box)(

  ({ theme }) => ({

    backgroundColor: theme.palette.primary.light,
    color: theme.palette.grey[900],
    padding: theme.spacing(2),
    textAlign: 'center',

    ":hover": {
      backgroundColor: theme.palette.primary.dark,
      color: theme.palette.grey[100],
    },

    ":active": {
      backgroundColor: theme.palette.warning.dark,
      color: theme.palette.grey[100],
    },


    // Pseudo select child element
    ":hover > div": {
      backgroundColor: theme.palette.error.dark,
    },


    // Pseudo select child component (We need to select the class or id which is used in the child component) 
    ":hover > .childComponent": {
      backgroundColor: theme.palette.success.dark,
    },

  })
)
```




&nbsp;

**CSS Like Syntax**

&nbsp;


```js
const PseudoClasses = styled(Box)(
  ({ theme }) => `
  background-color: ${theme.palette.primary.light};
  color: ${theme.palette.grey[900]};
  padding: ${theme.spacing(2)};
  text-align: center;


  :hover {
    background-color: ${theme.palette.primary.dark};
    color: ${theme.palette.grey[100]};
  };


  :active {
    background-color: ${theme.palette.warning.dark};
    color: ${theme.palette.grey[100]};
  };


  ${ /* Pseudo select child element  */'' }

  :hover > div  {
    background-color: ${theme.palette.error.dark};
  };


  ${ /* Pseudo select child component (We need to select the class or id which is used in the child component)   */'' }

  :hover > .childComponent {
    background-color: ${theme.palette.success.dark};
  };


 `,
)
```




&nbsp;

## Sibling Component

&nbsp;



**JSX**

&nbsp;

Suppose, we want the following `JSX`: 


```jsx
<>
  <MainComponent> Hello </MainComponent>
  <Box className='siblingComponent'> Hi </Box>
</>
```

So, we need to create the `MainComponent` and also need to style the sibling component `Box`.



&nbsp;

**JavaScript Object Syntax**

&nbsp;


```js
const MainComponent = styled(Box)(

  ({ theme }) => ({

    backgroundColor: theme.palette.primary.light,
    color: theme.palette.grey[900],

    // Adjacent Sibling Component (We need to use class or id of the Sibling component)
    "+ .siblingComponent": {
      backgroundColor: theme.palette.success.dark,
      color: theme.palette.grey[100]
    },

  })
)
```

> Note:
>
> - Instead of a sibling component, if there was a sibling HTML tag, we could have a style that too (`"+ div"`).
>
> - The adjacent sibling selector (`+`) is used to select an element that is directly after another specific element.


&nbsp;

**CSS Like Syntax**

&nbsp;


```js
const MainComponent= styled(Box)(

  ({ theme }) => `
  background-color: ${theme.palette.primary.light};
  color: ${theme.palette.grey[900]};


  ${ /* Adjacent Sibling Component (We need to use class or id of the Sibling component) */'' }

   + .siblingComponent {
    background-color: ${theme.palette.success.dark};
    color: ${theme.palette.grey[100]};
  };

 `,
)
```







&nbsp;

## Props

&nbsp;



&nbsp;

**JSX**

&nbsp;

Suppose, we want to have a component (`TestingProp`) where we can pass two props:  `dark` & `border`. The value of both props is boolean & the value will of these props controls the style of the component.

```jsx
   <>

   <TestingProps border={true} dark={true}>Hello
   </TestingProps>

  </>
```

So, we need to create the `TestingProps` component and also need work with the prop `dark` &  `border`.



&nbsp;

**JavaScript Object Syntax (Without MUI Theme)**

&nbsp;

```js
const TestingProps = styled(Box, {

    // Configure which props should be forwarded on DOM
   shouldForwardProp: (prop) => prop !== 'dark' && prop!== 'border'
 
   })
   
   (({ dark, border }) => ({
 
   backgroundColor: dark? "black" : "white",
   color: dark? "white" : "black",
   border: border? "1rem solid pink" : 'none'
 
   }));

```

> What is this `shouldForwaredProp`?
>
> We may already know that MUI5 uses emotion as a default style engine. This `shouldForwardProp` is coming from `emotion`. `shouldForwaredProp` is used to pass prop. In an example in the official documentation, `shouldForwaredProp` is used, you can [check](https://mui.com/system/styled/#custom-components) the example if you want.





&nbsp;

**CSS Like Syntax (Without MUI Theme)**

&nbsp;


```js
const TestingProps4 = styled(Box, {

  // Configure which props should be forwarded on DOM
  shouldForwardProp: (prop) => prop !== 'dark' && prop!== 'border'
   
  })
  

  (({ dark, border }) => `

    background-color: ${dark? "black" : "white"};
    color: ${dark? "white" : "black"};
    border: ${border? "1rem solid pink" : 'none'}
  
  `);

```


&nbsp;

**JavaScript Object Syntax (With MUI Theme)**

&nbsp;

```js
const TestingProps = styled(Box, {

   // Configure which props should be forwarded on DOM
  shouldForwardProp: (prop) => prop !== 'dark' && prop!== 'border'

  })
  
  (({ dark, border, theme }) => ({

  backgroundColor: dark? theme.palette.grey[900] : theme.palette.grey[100],
  color: dark? theme.palette.grey[100] : theme.palette.grey[900],
  border: border? `1rem solid ${theme.palette.primary.main}` : 'none'

  }));

```


&nbsp;

**CSS Like Syntax (With MUI Theme)**

&nbsp;


```js
const TestingProps = styled(Box, {

   // Configure which props should be forwarded on DOM
   shouldForwardProp: (prop) => prop !== 'dark' && prop!== 'border'

  })
  

  (({ dark, border, theme }) => `

    background-color: ${dark? theme.palette.grey[900] : theme.palette.grey[100]};
    color: ${dark? theme.palette.grey[100] : theme.palette.grey[900]};
    border: ${border? `1rem solid ${theme.palette.primary.main}` : 'none'};
  
  `);

```



&nbsp;

**Default Prop Value**

&nbsp;

We can also pass the default value for the props.

```js
TestingProps.defaultProps = {
    dark: false,
    border: false
  }

```



&nbsp;

![rich-text-editor-for-react npm package](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/scz09ynfwbdvqflj9ssh.png)
>[Demo](https://rich-text-editor-for-react.rasaf-ibrahim.com) | [Documentation](https://docs.rich-text-editor-for-react.rasaf-ibrahim.com)



&nbsp;







&nbsp;
##  sx Prop can be used as an Alternative to the styled Utility

&nbsp;

**Setup**

With the right setup, the `sx` prop can replicate all functionalities provided by the `Styled` utility:

```jsx
const NewStyledComponent = (props) => {
   const {sx, children, ...extra_props} = props;

   return (
      <Box 
        sx={{
            backgroundColor: 'black',
            ...sx
        }}
        {...extra_props}
      >
        {children}
      </Box> 
   );
}
```

&nbsp;

**How the Above Setup Ensures the Functionalities of the `styled` Utility**

&nbsp;

- The component accepts and renders `children`, allowing content to be placed inside, similar to a component created using the styled utility.
  
- Just as components created with the styled utility can accept the `sx` prop for additional styling, "NewStyledComponent" also accepts the `sx` prop. 
  
- The `...extra_props` in "NewStyledComponent" allows for the forwarding of any additional props to the Box component. For instance, props like "onSubmit" and "onClick" can be seamlessly passed and applied. This behavior aligns with components from the styled utility, which also accept a diverse range of props for various scenarios.
  
&nbsp;

**Additional Advantages of the `sx` Prop Approach**

&nbsp;

- Conditional styling becomes more straightforward because we are essentially creating a standard React component. This allows us to accept and pass props as we typically would, without following the specific prop-accepting conventions of the styled utility.

&nbsp;

- Working with media queries becomes more straightforward:


```jsx
const NewStyledComponent = (props) => {
   const {sx, children, ...extra_props} = props;

   return (
      <Box 
        sx={{
            // media query
            width: { xs: '15rem', sm: '12rem' },
            ...sx
        }}
        {...extra_props}
      >
        {children}
      </Box> 
   );
}
```

&nbsp;

- Accessing the theme does not pose much difficulty:

```jsx
const NewStyledComponent = (props) => {
   const {sx, children, ...extra_props} = props;

   return (
      <Box 
        sx={(theme) => ({
            // accessing theme
            backgroundColor: theme.palette.primary.main,
            ...sx
        })}
        {...extra_props}
      >
        {children}
      </Box> 
   );
}
```



&nbsp;

---

&nbsp;

That's it. 😃 Thanks for reading. 🎉