The Essential Guide to MUI Styled Components

Material-UI version 5 made the styled API one of two primary component styling APIs. Unfortunately, the complexity of styled componenents in Material-UI increased exponentially. For example, now developers must decide:

  • Should I use the styled API that wraps emotion?
  • Should I use the styled API that wraps styled-components?
  • Should I use styled components directly in Material-UI?
  • Should I import @mui/styled-engine, @mui/styled-engine-sc, @mui/system, or @mui/material/styles?
  • Which of the seven new options should I pass as options to styled? For reference, the typing is styled(Component, [options])(styles) => Component.

My goal with this guide is to aid the 90% of developers who want a simple setup for using Styled Components with MUI. I will include links to resources that go beyond the scope of the setup demonstrated in this article.

If you are debating using styled components vs the sx prop, the short answer is that styled components are meant to be created and exported for reuse all throughout your app. The sx prop is a quicker styling method that is intended to replace local classes and inline styling. In reality, they can both accomplish the same goals and in my opinion it comes down to developer preference. Here’s a full article on MUI sx vs styled vs theme overrides and when to use each.

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

You can view a video version of this post on YouTube or below:

MUI Styled Import

Most developers should use the MUI-recommended approach, which is the styled() API that wraps emotion.

  • This avoids having to configure package.json dependencies and tsconfig.json.
  • The styling syntax is identical and the MUI documentation directs users to the same guide for both emotion and styled-components.

Here is the simplest import for the styled() emotion wrapper: import { styled } from "@mui/system";

Importing from "@mui/material/styles"; imports the same object. There is no difference in "@mui/system" vs "@mui/material/styles". Interestingly, according to my analytics from Google, importing from “@mui/material/styles” is searched almost 30X more than "@mui/system".

If you do want to switch completely to styled-components instead of emotion, here’s the MUI guide. Your actual styling code will be identical.

MUI Styled Component Example

I created a simple styled Paper component that wraps a button.

MUI Paper Styled Component
MUI Paper Styled Component

Here’s the code, I will discuss it below. Also notice StyledPaper and StyledPaper2 show the two different valid syntaxes for Styled Components in Material-UI.

import * as React from "react";
import Paper from "@mui/material/Paper";
import Button from "@mui/material/Button";
import { styled } from "@mui/system";

//notice the syntax
const StyledPaper = styled(Paper, {
  name: "StyledPaper",
  slot: "Wrapper"
})({
  color: "#6B8068",
  //backgroundImage: `url("https://picsum.photos/200/300")`,
  backgroundColor: "silver",
  margin: "auto",
  borderRadius: 2,
  height: 300,
  display: "flex",
  alignItems: "center",
  justifyContent: "center",
  ".MuiButton-root": { color: "#FF0000" }
});

//Tick mark syntax also works
const StyledPaper2 = styled(Paper, {
  name: "StyledPaper2",
  slot: "Wrapper"
})`
  color: red;
  height: 300px;
  background-image: url("https://picsum.photos/200/300");
`;

export default function StyledPaperExample() {
  return (
    <StyledPaper>
      <Button variant="outlined">Text</Button>
    </StyledPaper>
    //<StyledPaper2>
    // Text
    //</StyledPaper2>
  );
}

The StyledPaper component uses JavaScript syntax that looks like JSS. The StyledPaper2 component uses CSS syntax wrapped in ticks.

This Styled Component had several interesting features:

  • background color
  • background image
  • flex
  • nested selectors

Take note of the slight difference in syntax between the two methods. For example, the traditional styled component syntax for background image is shown in StyledPaper2: background-image. But it also works to pass backgroundImage as a field name in an object using JavaScript syntax.

An important feature of the styled() API is that it allows direct access to the theme. I could have set color with the following code: color: ${theme.palette.primary.main};. This is available in both the JSS and CSS syntaxes above. To access the theme, pass the theme to the styled component.

MUI Styled Nested Selectors

Nested selectors are as simple in the MUI styled API as they are in the sx API. Simply pass the targeted selector and the value: ".MuiButton-root": { color: "#FF0000" }.

Nested selectors are often used to target composite components. Composite components are components constructed of multiple MUI subcomponents. You could think of them as a wrapper with nested components. The TextField is a good example of this. It is a FormControl, Input, InputLabel, and potentially more components.

Styled Component Options

If you want to read about each option, see the docs here. If not, here’s a quick overview:

  • Two of the props disable other ‘normal’ MUI component features (sx prop and the ability to create variants)
  • Three of the options are used for labeling or naming your component in the DOM or style sheet.
  • The remaining two options deal with forwarding props to the underlying component

MUI shouldForwardProp

I expect most devs won’t need to pass any options. However, the shouldForwardProp option may be useful when you need to control exactly how passed props interact with the underlying component.

In my example above, I used name and slot component to change the CSS class name generated for my component. It was pretty cool!

Styled Components DOM CSS name
Styled Components DOM CSS name

MUI Styled Props

Props can be passed to the styling API and used for styling the component. ‘Common’ MUI props can also be passed to the underlying component, given that they are not blocked by the shouldForwardProp option. We’ll explore both below.

Passing Props to Styled API

The syntax is a little tricky for passing styling props. Here’s the previous example code, but instead of setting the background color directly, we will use a prop called myColor:

const StyledPaper = styled(Paper, {
  name: "StyledPaper",
  slot: "Wrapper"
})((props) => ({
  color: "#6B8068",
  backgroundColor: props.myColor,
  margin: "auto",
  borderRadius: 2,
  height: 300,
  display: "flex",
  alignItems: "center",
  justifyContent: "center",
  ".MuiButton-root": { color: "#FF0000" }
}));

That’s a lot of parenthesis and curly braces! But they are all necessary for passing the component, the options, and the styling (with access to props) to the `styled` API.

And here’s how the prop is set on the component:

<StyledPaper myColor="green">
  <Button variant="outlined">Text</Button>
</StyledPaper>

A common use case might be to set styling based on dynamically calculated props.

Passing MUI Props to Styled Components

Props that are part of a MUI component’s API are still easily passed to the underlying component when using a styled component.

For example, Paper is the underlying component for StyledPaper. I will pass the elevation and sx prop and both can be applied in addition to whatever styling was applied through the `styled` API.

<StyledPaper elevation={12} sx={{ marginBottom: 3 }}>
  <Button variant="outlined">Text</Button>
</StyledPaper>

However, props can also be disabled using the shouldForwardProp of the styled API.

const StyledPaper = styled(Paper, {
  name: "StyledPaper",
  slot: "Wrapper",
  shouldForwardProp: (prop) => {
    return prop !== "elevation";
  }
))

In this case, I blocked elevation from passing through. Take a look at the screenshot below. The top StyledPaper component has bottom margin (received from the sx prop) but did not receive the elevation prop.

I expect the most likely use case for blocking props is if a team wants to maintain a rigid styling system for their UI.

Resources

This MUI tutorial shows an app created with both styling APIs.

Here’s how to add hover to a Material-UI Button using styled-components.

Interestingly, the MUI Tooltip could only be styled with the Styled API, not with sx.

Here’s how to add box-shadow to MUI components with sx or the styled API.

Code Sandbox Link

Material-UI Styled Documentation

Share this post:

4 thoughts on “The Essential Guide to MUI Styled Components”

  1. I am wrapping some Mui components and I just want to set a standard Mui class name if a custom prop is true.
    interface MyButtonProps extends ButtonProps { readOnly: boolean; };
    export const MyButton = styled(Button)({theme}) => ({
    if (props.readOnly) applyClass(“MuiDisabled”);
    });

    Reply
    • Hi Benjamin, interesting approach. I have never tried that and do not know if it will work….but I do know you could pass the readOnly prop to the underlying disabled prop on MyButton and it will apply the MuiDisabled class automatically.

      Reply

Leave a Comment

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