The Ultimate Guide to the MUI ‘sx’ Prop

Material-UI (rebranded as MUI) recently released version 5, and there were significant changes to the syntax and systems used for styling components.

Material-UI v4 relied on JSS and the makeStyles hook for component styling. MUI v5 has migrated to two options: styled API or sx API (<- definitely read this). The styled API creates a new component that can easily be exported, and usage of the component is very clean with less inline prop code. The sx prop is a superset of CSS that include built-in shorthands (i.e. mt={2} sets margin-top).

Both of the new APIs offer the following advantages over makeStyles:

  • One less import: the @material-ui/core/styles import is no longer needed
  • Less boiler-plate code: the makeStyles() and useStyles syntax are no longer needed and it results in several fewer lines of code written for each component
  • Better abstraction: sx and styled both offer unique abstractions that simplify your code. sx requires less code to do more styling, while styled offers simplified reusability. I’ll explain this in-depth in the last section

If you want to see the stlyed API in action, I used it to change color on hover in MUI buttons here.

makeStyles is still supported, but it is deprecated. If you want to use it, it now requires the @mui/styles import.

A Code Sandbox link with full React code is in the Resources section. Watch the YouTube version of this article here.

The Purpose of the ‘sx’ Prop

Since MUI 5 created a new styling API, the primary questions to ask are “What is the sx prop and why should I use it?”. The docs explain it simply:

The `sx` prop is a shortcut for defining custom style that has access to the theme.

MUI sx prop docs

The sx prop simply requires very little code to accomplish lots of styling.

  • Superset of CSS – sx can accept all CSS attributes (using JSS syntax) and it can accept all values from the “MUI System“. This is a vague name for their extensive list of rapid styling shortcuts.
  • As mentioned above, it reduced the amount of code required for styling by getting rid of the makeStyles hook
  • Theme aware – theme values can be accessed quickly. sx={{ zIndex: 'modal' }} is accessing theme.zIndex.modal.
  • Easy responsive styling – properties in sx can accept an object of with breakpoints as the key and CSS values as the values (an example is in the next section)

Example Code for the New MUI 5 ‘sx’ Prop

I created the below TextField components only using styles passed to the sx prop. The first is the ‘filled’ variant and the second is the ‘standard’ variant.

In each section below I’ll break down the different aspects of the styling code in the sx props of these TextFields.

import * as React from "react";
import TextField from "@mui/material/TextField";

const style = {
  mt: 2,
  ml: 2,
  width: { sm: 200, md: 300 },
  backgroundColor: { xs: "secondary.light", sm: "#0000ff" },
  boxShadow: 6
};

export default function CustomStyledTextField() {
  return (
    <>
      <TextField
        sx={{
          ...style,
          mb: 2,
          mr: 2,
          border: "solid black 2px",
          "& .MuiFilledInput-input": { color: "white" }
        }}
        id="standard-basic"
        label="Filled"
        variant="filled"
      />
      <TextField
        sx={{
          ...style,
          "& .MuiOutlinedInput-root:hover": {
            "& > fieldset": {
              borderColor: "orange"
            }
          }
        }}
        id="standard-basic"
        label="standard"
        variant="outlined"
      />
    </>
  );
}

Extracting Shared Styles With Consts and Object Destructuring

An important syntax option available in es6 is object destructuring. It gives us a quick way to extract shared styles to a constant that can be reused.

const style = {//shared styling goes here}

sx={{
  ...style,
  mb: 2,
  mr: 2,
  //etc
}}

Both of the TextFields have common styling. We certainly don’t want to copy/paste code, se we extract it. In the sx prop after destructuring the style const, simply include any additional styling specific to that TextField.

Superset and CSS Values

Below are some of the values in the ‘filled’ variant.

mb: 2, //System
mr: 2, //System
border: "solid black 2px" //CSS

mb is margin-bottom and mr is margin-right. These are shorthands available in the “MUI System”. Next is border, which is standard CSS. These properties coexist and are equally viable in the sx prop. This is why the prop is a ‘superset’ of CSS: all CSS values are valid, plus additional values from MUI’s styling system are valid.

Breakpoints

Breakpoints in the sx prop are actually objects within a style value that map to theme breakpoints.

backgroundColor: { xs: "secondary.light", sm: "#0000ff" }

The xs and sm above have values of 0 and 600, respectively, in my code. These are the default values of the MUI theme object’s breakpoints. These can be customized.

Accessing the Theme

In the breakpoints code above, notice the xs value: "secondary.light". This is shorthand for theme.palette.secondary.light.

Even the way I accessed the breakpoints is a shorthand for accessing theme.breakpoints.values.xs (or .sm).

Nested Components

One of my favorite aspects of the sx component is that it has the capability to use complex CSS selectors.

"& .MuiFilledInput-input": { color: "white" }

This selects children elements with class .MuiFilledInput-input.

The TextField is composed of several components, which means in the DOM it is composed of several elements. It’s important to know that sx styles are applied to the topmost element possible in the DOM.

The screenshot couldn’t quite capture all the styling, but further down in the list of stylings we would see the styles we gave to the sx prop. They are all applied to the root div of the TextField. A child element further down in the DOM has class .MuiFilledInput-input.

Pseudo-Classes and Pseudo-Elements

I created a complex selector that only applies hover to the ‘outlined’ variant. This requires the :hover pseudo-class to be part of the selector. It will apply a border color to the MUI TextField.

sx={{
  ..styles,
  "& .MuiOutlinedInput-root:hover": {
    "& > fieldset": {
      borderColor: "orange"
    }
  }
}}

The .MuiOutlinedInput-root class is only available on the ‘outlined’ variant. So is the fieldset element. This code selects fieldset elements that are children of elements with .MuiOutlinedInput-root and :hover applied.

An important consideration is that I could have included this selector in the styles object if I was going to style multiple ‘outlined’ TextFields. I would still be able to apply the styles object to all TextFields, and this selector simply wouldn’t find anything to select on other TextField variants. I encourage you to take a look at the Code Sandbox link in the Resources section, open dev tools, and explore how MUI has rendered the TextField.

sx API vs styled API

If you’ve upgraded to MUI 5 and are wondering which of the two styling options are better, review this rundown of relative strengths:

styled API:

  • With styled, You get to write CSS….using CSS syntax. sx still uses JSS because it lives in JSX world.
  • styled is a simpler abstraction. In this example, all the Root component code is pulled out of the JSX. In practice, it should be in its own file and the Root component would simply be imported where needed. Similar abstraction can be accomplished with sx but it’s not the purpose of the sx API.
  • The styled library is a popular library with about 3 million weekly downloads (Sept 2021). Many devs will be familiar with it.

sx API:

  • It can be passed typical CSS attributes as well as all in-house MUI spacing shorthands (see the list here)
  • It simplifies access to the theme, i.e. 'primary.main' instead of theme.palette.primary.main.
  • Responsive styling is incredibly easy and requires very little code

Resources

Code Sandbox Link

The sx prop

The system

Share this post:

Leave a Comment

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