Material-UI makeStyles, useStyles, createStyles, and withStyles Explained

Styling hooks in Material-UI are an effective and exceptional tool for customizing components. However, the similarly-named hooks can be confusing to use.

In this post, I’ll explain what each hook does, when to use it, and which hooks are recommended for certain situations.

***MUI 5 UPDATE: There is a new styling system in MUI 5. I have updated this post with information about the new styling system.

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

Watch the YouTube version of this article or watch the embedded video below:

Material UI Styles Explained: makeS...
Material UI Styles Explained: makeStyles, useStyles, withStyles, and createStyles

Material-UI withStyles

React had not yet introduced hooks back when Material-UI 3 was first released. Higher-order components were still a common method of adding functionality to base components.

Material-UI withStyles was the primary method for wrapping a component and passing style props to it. It is still a valid method to use today if for some reason you are still using higher-order components or still using React lifecycle methods.

However, it is not the ideal method. Preferably, you are using React hooks and the MUI makeStyles hook (more on that below). Another recommended method of component styling is to use StyledComponents. Here’s a very basic example of creating a StyledComponent.

Below is an example of using withStyles:

Material-UI withStyles Example
Material-UI withStyles
import React from "react";
import PropTypes from "prop-types";
import { withStyles } from "@material-ui/core/styles";
import Button from "@material-ui/core/Button";

const styles = {
  root: {
    borderRadius: 12,
    backgroundColor: "blue"
  }
};

function HOCComponent(props) {
  const { classes } = props;
  return (
    <Button variant="contained" className={classes.root}>
      Higher-Order Button
    </Button>
  );
}

HOCComponent.propTypes = {
  classes: PropTypes.object.isRequired
};

export default withStyles(styles)(HOCComponent);

In my opinion, this is more confusing and verbose than the newer makeStyles hook.

Material-UI makeStyles

***UPDATE makeStyles is still supported in MUI 5 but is considered “legacy”. There is a new styling system. It is actually really easy to use and requires less code. I highly recommend taking a look.

The makeStyles hook is the current (V4) “proper” way to create styles for components. The underlying logic is the same as withStyles according to the docs.

There’s one less import needed for makeStyles compared to withStyles (not shown in my code below). It’s also a few lines less of code and more readable in my opinion.

Material-UI makeStyles Example
Material-UI makeStyles
import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import Button from "@material-ui/core/Button";

const useStyles = makeStyles({
  root: {
    borderRadius: 12,
    backgroundColor: "blue"
  }
});

function HookComponent(props) {
  const classes = useStyles();
  return (
    <Button variant="contained" className={classes.root}>
      Hook Button
    </Button>
  );
}

export default HookComponent;

Importantly, makeStyles can be passed parameters to make styling dynamic. For example, I passed a prop for height in order to position a Material-UI Drawer inside a container in the linked article.

Material-UI’s styles can also be used in React applications independently of the rest of the MUI package. If you export @material-ui/core/styles it will include a default theme; @material-ui/styles will not.

Here are 5 examples of hover selectors using makeStyles.

Material-UI useStyles

In the docs we find detailed explanations of different styling syntax, and we always see makeStyles paired with useStyles. However, we never get an explanation of useStyles.

useStyles is simply the naming convention of the hook created and returned by makeStyles. useStyles definitely is a hook; try calling it outside of the function component and you will get an error.

useStyles can be used to pass params to makeStyles, as mentioned above.

Material-UI createStyles

createStyles is perhaps the most interesting of the four topics in this post because it is a fix to make TypeScript play nicely with MUI.

“Its only purpose is to defeat TypeScript‘s type widening when providing style rules to makeStyles/withStyles which are a function of the Theme.”

MUI Docs

The docs even mention that the createStyles function doesn’t do anything at runtime.

The docs go into a pretty long explanation here. Suffice to say, I appreciate that the MUI team came up with a quick way to appease TypeScript.

Here’s example usage from the docs quoted above:

const useStyles = makeStyles((theme: Theme) => createStyles({
  root: {
    backgroundColor: theme.color.red,
  },
}));

How to Use Props, Theme, and TypeScript with MUI makeStyles

Here’s a final makeStyles (MUI v4) example that passes a props object to makeStyles, uses the default theme, and requires TypeScript typing for both. The result is once again a button with background color and border radius styling.

First, I set the file type to .tsx. If TypeScript is included in the project, this indicates that I want typing run against the file. Next, I imported createStyles, makeStyles, and the Theme object from "@material-ui/core/styles". TypeScript did not throw any errors even when I did not use createStyles, but I used it just for a learning experience.

My first goal was to pass a prop into makeStyles using the useStyles hook. Looking at the code below, you can see that I passed { radius: 12 } in the useStyles call. This made props available to the makeStyles hook and the props were accessible for a style property through use of an arrow function. However, when I attempted to access props.radius, I got a TypeScript error.

I needed to type the props. This protects me against trying to access a value that does not exist. I created an interface named styleProps and added radius: number;, informing the compiler that it is safe to access props.radius.

My second goal was to include the theme. This was done by passing an arrow function to makeStyles with typed prop theme: Theme. The theme was not passed as an additional prop through useStyles, see the code below to understand the difference between theme and additional props. Once theme was made available, it could be accessed by a style property such as backgroundColor without using an arrow function.

import React from "react";
import { createStyles, makeStyles, Theme } from "@material-ui/core/styles";
import Button from "@material-ui/core/Button";

interface styleProps {
  radius: number;
}

const useStyles = makeStyles((theme: Theme) =>
  createStyles({
    root: {
      borderRadius: (props: styleProps) => props.radius,
      backgroundColor: theme.palette.primary.main
    }
  })
);

function HookComponent() {
  const classes = useStyles({ radius: 12 });
  return (
    <Button variant="contained" className={classes.root}>
      Hook Button
    </Button>
  );
}

export default HookComponent;

MUI 5 ‘sx’ Prop, styled() API, and the Styling System

MUI 5 offers a new styling system that has many advantages:

  • Less boiler-plate code
  • All CSS attributes and all MUI style shorthands are accessible in one prop
  • Easier access to the MUI theme
  • Easier responsive styling with breakpoints

While it can be a headache to switch, the MUI team created some great documentation. Furthermore, I think the new system has some great benefits.

You can read my detailed guide to the sx prop here, and my essential guide to the styled() API here. The sx prop is meant for quick local styling, while the styled() API is intended for creating components for reuse and export. Furthermore, the styled() API should be familiar to developers who have used the styled-components library.

This MUI tutorial shows an app created with both styling APIs and discusses the pros and cons.

How to use makeStyles in MUI v5

My article “The Ultimate Guide to Material-UI Grid Containers and Items (MUI v5)” has a direct comparison of how to style the root of a Grid using makeStyles and how to style using the sx prop. I pasted the significant code differences below:

//makeStyles

import { makeStyles } from "@mui/styles";

const useStyles = makeStyles({
  root: {
    backgroundColor: "blue",
    paddingBottom: 16,
    paddingRight: 16,
    marginTop: 16,
    marginLeft: "auto",
    marginRight: "auto",
    maxWidth: 500
  }
});

export default function FullWidthGrid() {
  const classes = useStyles();
  return (
    <>
      <Grid
        container
        className={classes.root}
    //Additional JSX
      </Grid>
  );
}



//sx prop

const gridStyles = {
  backgroundColor: "blue",
  paddingBottom: 2,
  paddingRight: 2,
  marginTop: 2,
  marginLeft: "auto",
  marginRight: "auto",
  maxWidth: 500
};

export default function FullWidthGrid() {
  return (
    <>
      <Grid
        container
        sx={gridStyles}
    //Additional JSX
      </Grid>
  );
}

The primary change in MUI v5 for makeStyles is that now it is imported using import { makeStyles } from "@mui/styles"; . Notice also that it does not plug directly into the system values. For example, I had to use paddingRight: 16 with makeStyles, but I was able to use paddingRight: 2 with the sx prop.

Resources

Here’s a full article on MUI sx vs styled vs theme overrides and when to use each.

My MUI course on Udemy is now available!!! Build a full MUI app from beginning to end, learn every aspect of the sx prop, styled API, and the theme, and tackle the most challenging components! Do you want an active Q&A with me?!? Check here for coupons for my MUI course on Udemy.

Learn how MUI v5 sx and styled API both rely on Emotion.

Code Sandbox Link

Share this post:

4 thoughts on “Material-UI makeStyles, useStyles, createStyles, and withStyles Explained”

  1. Great article! I wish I had found and read it when I started using MUI a year and a half ago.

    Btw: Was your inclusion of the line:
    const classes = useStyles()
    in the example “sx prop” a typo? I don’t see the use of it.

    Reply

Leave a Comment

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