Files
react-test/docs/data/material/migration/migration-v4/migrating-from-jss.md
how2ice 005cf56baf
Some checks failed
No response / noResponse (push) Has been cancelled
CI / Continuous releases (push) Has been cancelled
CI / test-dev (macos-latest) (push) Has been cancelled
CI / test-dev (ubuntu-latest) (push) Has been cancelled
CI / test-dev (windows-latest) (push) Has been cancelled
Maintenance / main (push) Has been cancelled
Scorecards supply-chain security / Scorecards analysis (push) Has been cancelled
CodeQL / Analyze (push) Has been cancelled
init project
2025-12-12 14:26:25 +09:00

15 KiB

Migrating from JSS (optional)

This guide explains how to migrate from JSS to Emotion when updating from Material UI v4 to v5.

Material UI v5 migration

  1. Getting started
  2. Breaking changes part one: style and theme
  3. Breaking changes part two: components
  4. Migrating from JSS 👈 you are here
  5. Troubleshooting

Migrating from JSS to Emotion

One of the biggest changes in v5 is the replacement of JSS for Emotion (or styled-components as an alternative) as a default styling solution .

Note that you may continue to use JSS for adding overrides for the components (for example makeStyles, withStyles) even after migrating to v5. Then, if at any point you want to move over to the new styling engine, you can refactor your components progressively.

:::info If you are using Next.js and you are not sure how to configure SSR to work with both Emotion & JSS, take a look a this example project. :::

This document reviews all the steps necessary to migrate away from JSS.

While you can use either of the following two options, the first is considered preferable:

1. Use styled or sx API

Codemod

We provide a codemod to help migrate JSS styles to styled API, but this approach increases the CSS specificity.

:::info Normally you wouldn't write styles like this. But this is the best transformation that we could create with a codemod.

If you want to refine them later, you can refer to the examples shown in the sections below. :::

npx @mui/codemod@latest v5.0.0/jss-to-styled <path>

Example transformation:

 import Typography from '@mui/material/Typography';
-import makeStyles from '@mui/styles/makeStyles';
+import { styled } from '@mui/material/styles';

-const useStyles = makeStyles((theme) => ({
-  root: {
-    display: 'flex',
-    alignItems: 'center',
-    backgroundColor: theme.palette.primary.main
-  },
-  cta: {
-    borderRadius: theme.shape.radius
-  },
-  content: {
-    color: theme.palette.common.white,
-    fontSize: 16,
-    lineHeight: 1.7
-  },
-}))
+const PREFIX = 'MyCard';
+const classes = {
+  root: `${PREFIX}-root`,
+  cta: `${PREFIX}-cta`,
+  content: `${PREFIX}-content`,
+}
+const Root = styled('div')(({ theme }) => ({
+  [`&.${classes.root}`]: {
+    display: 'flex',
+    alignItems: 'center',
+    backgroundColor: theme.palette.primary.main
+  },
+  [`& .${classes.cta}`]: {
+    borderRadius: theme.shape.radius
+  },
+  [`& .${classes.content}`]: {
+    color: theme.palette.common.white,
+    fontSize: 16,
+    lineHeight: 1.7
+  },
+}))

 export const MyCard = () => {
-  const classes = useStyles();
   return (
-    <div className={classes.root}>
+    <Root className={classes.root}>
       {/* The benefit of this approach is that the code inside Root stays the same. */}
       <Typography className={classes.content}>...</Typography>
       <Button className={classes.cta}>Go</Button>
-    </div>
+    </Root>
   )
 }

:::success You should run this codemod on a small chunk of files and then check the changes before continuing, because in some cases you might need to adjust the code after the transformation—this codemod won't cover all cases. :::

Manual

We recommend sx API over styled for creating responsive styles or overriding minor CSS. Read more about sx here.

 import Chip from '@mui/material/Chip';
-import makeStyles from '@mui/styles/makeStyles';
+import Box from '@mui/material/Box';

-const useStyles = makeStyles((theme) => ({
-  wrapper: {
-    display: 'flex',
-  },
-  chip: {
-    padding: theme.spacing(1, 1.5),
-    boxShadow: theme.shadows[1],
-  }
-}));

 function App() {
-  const classes = useStyles();
   return (
-    <div className={classes.wrapper}>
-      <Chip className={classes.chip} label="Chip" />
-    </div>
+    <Box sx={{ display: 'flex' }}>
+      <Chip label="Chip" sx={{ py: 1, px: 1.5, boxShadow: 1 }} />
+    </Box>
   );
 }

In some cases, you might want to create multiple styled components in a file instead of increasing CSS specificity.

For example:

-import makeStyles from '@mui/styles/makeStyles';
+import { styled } from '@mui/material/styles';

-const useStyles = makeStyles((theme) => ({
-  root: {
-    display: 'flex',
-    alignItems: 'center',
-    borderRadius: 20,
-    background: theme.palette.grey[50],
-  },
-  label: {
-    color: theme.palette.primary.main,
-  }
-}))
+const Root = styled('div')(({ theme }) => ({
+  display: 'flex',
+  alignItems: 'center',
+  borderRadius: 20,
+  background: theme.palette.grey[50],
+}))

+const Label = styled('span')(({ theme }) => ({
+  color: theme.palette.primary.main,
+}))

 function Status({ label }) {
-  const classes = useStyles();
   return (
-    <div className={classes.root}>
-      {icon}
-      <span className={classes.label}>{label}</span>
-    </div>
+    <Root>
+      {icon}
+      <Label>{label}</Label>
+    </Root>
   )
 }

:::success This jss-to-styled tool helps convert JSS to multiple styled components without increasing CSS specificity.

This tool is not maintained by MUI. :::

2. Use tss-react

:::error This API will not work if you are using styled-components as the underlying styling engine in place of @emotion. :::

The API is similar to JSS makeStyles, but under the hood, it uses @emotion/react. It also features much better TypeScript support than v4's makeStyles.

In order to use it, you'll need to add it to your project's dependencies:

With npm:

npm install tss-react

With yarn:

yarn add tss-react

Codemod

We provide a codemod to help migrate JSS styles to the tss-react API.

npx @mui/codemod@latest v5.0.0/jss-to-tss-react <path>

Example transformation:

 import * as React from 'react';
-import makeStyles from '@material-ui/styles/makeStyles';
+import { makeStyles } from 'tss-react/mui';
 import Button from '@mui/material/Button';
 import Link from '@mui/material/Link';

-const useStyles = makeStyles((theme) => {
+const useStyles = makeStyles()((theme) => {
   return {
     root: {
       color: theme.palette.primary.main,
     },
     apply: {
       marginRight: theme.spacing(2),
     },
   };
 });

 function Apply() {
-  const classes = useStyles();
+  const { classes } = useStyles();

   return (
     <div className={classes.root}>
       <Button component={Link} to="https://support.mui.com" className={classes.apply}>
         Apply now
       </Button>
     </div>
   );
 }

 export default Apply;

If you were using the $ syntax and clsx to combine multiple CSS classes, the transformation would look like this:

 import * as React from 'react';
-import { makeStyles } from '@material-ui/core/styles';
-import clsx from 'clsx';
+import { makeStyles } from 'tss-react/mui';

-const useStyles = makeStyles((theme) => ({
+const useStyles = makeStyles<void, 'child' | 'small'>()((theme, _params, classes) => ({
   parent: {
     padding: 30,
-    '&:hover $child': {
+    [`&:hover .${classes.child}`]: {
       backgroundColor: 'red',
     },
   },
   small: {},
   child: {
     backgroundColor: 'blue',
     height: 50,
-    '&$small': {
+    [`&.${classes.small}`]: {
       backgroundColor: 'lightblue',
       height: 30
     }
   },
 }));

 function App() {
-  const classes = useStyles();
+  const { classes, cx } = useStyles();
   return (
     <div className={classes.parent}>
       <div className={classes.child}>
         Background turns red when the mouse hovers over the parent.
       </div>
-      <div className={clsx(classes.child, classes.small)}>
+      <div className={cx(classes.child, classes.small)}>
         Background turns red when the mouse hovers over the parent.
         I am smaller than the other child.
       </div>
     </div>
   );
 }

 export default App;

:::error When using JavaScript (rather than TypeScript), remove <void, 'child' | 'small'>. :::

The following is a comprehensive example using the $ syntax, useStyles() parameters, merging in classes from a classes prop (see doc) and an explicit name for the stylesheet.

-import clsx from 'clsx';
-import { makeStyles, createStyles } from '@material-ui/core/styles';
+import { makeStyles } from 'tss-react/mui';

-const useStyles = makeStyles((theme) => createStyles<
-  'root' | 'small' | 'child', {color: 'primary' | 'secondary', padding: number}
->
-({
-  root: ({color, padding}) => ({
+const useStyles = makeStyles<{color: 'primary' | 'secondary', padding: number}, 'child' | 'small'>({name: 'App'})((theme, { color, padding }, classes) => ({
+  root: {
     padding: padding,
-    '&:hover $child': {
+    [`&:hover .${classes.child}`]: {
       backgroundColor: theme.palette[color].main,
     }
-  }),
+  },
   small: {},
   child: {
     border: '1px solid black',
     height: 50,
-    '&$small': {
+    [`&.${classes.small}`]: {
       height: 30
     }
   }
-}), {name: 'App'});
+}));

 function App({classes: classesProp}: {classes?: any}) {
-  const classes = useStyles({color: 'primary', padding: 30, classes: classesProp});
+  const { classes, cx } = useStyles({
+    color: 'primary',
+    padding: 30
+  }, {
+    props: {
+      classes: classesProp
+    }
+  });

   return (
     <div className={classes.root}>
       <div className={classes.child}>
         The Background take the primary theme color when the mouse hovers the parent.
       </div>
-      <div className={clsx(classes.child, classes.small)}>
+      <div className={cx(classes.child, classes.small)}>
         The Background take the primary theme color when the mouse hovers the parent.
         I am smaller than the other child.
       </div>
     </div>
   );
 }

 export default App;

After running the codemod, search your code for "TODO jss-to-tss-react codemod" to find cases that the codemod could not handle reliably.

There may be other cases beyond those with TODO comments that are not handled fully by the codemod—particularly if parts of the styles are returned by functions.

If the styles buried within a function use the $ syntax or useStyles params, then those styles won't be migrated appropriately.

:::error You should drop clsx in favor of cx.

The key advantage of cx is that it detects Emotion-generated class names to ensure that styles are overwritten in the correct order.

The default precedence of styles from multiple CSS classes is different between JSS and tss-react and some manual re-ordering of cx parameters may be necessary—see this issue comment for more details. :::

To ensure that your class names always includes the actual name of your components, you can provide the name as an implicitly named key (name: { App }).

See this tss-react doc for details.

You may end up with ESLint warnings like this one if you deconstruct more than one item.

Don't hesitate to disable eslint(prefer-const), like this in a regular project.

withStyles()

tss-react also features a type-safe implementation of v4's withStyles().

:::info The equivalent of the $ syntax is also supported in tss's withStyles(). See doc. :::

-import Button from '@material-ui/core/Button';
+import Button from '@mui/material/Button';
-import withStyles from '@material-ui/styles/withStyles';
+import { withStyles } from 'tss-react/mui';

 const MyCustomButton = withStyles(
+  Button,
   (theme) => ({
     root: {
       minHeight: '30px',
     },
     textPrimary: {
       color: theme.palette.text.primary,
     },
     '@media (min-width: 960px)': {
       textPrimary: {
         fontWeight: 'bold',
       },
     },
   }),
-)(Button);
+);

 export default MyCustomButton;

Theme style overrides

Global theme overrides are supported out of the box by TSS.

Follow the instructions in the relevant section of the Breaking changes doc, and provide a name to makeStyles.

In Material UI v5, style overrides also accept callbacks.

By default, TSS is only able to provide the theme. If you want to provide the props and the ownerState, please refer to this documentation.

:::warning tss-react is not maintained by MUI.

If you have any question about how to setup SSR (Next.js), or if you are wondering how to customize the theme object, please refer to the tss-react documentation.

You can also submit an issue for any bug or feature request, and start a discussion if you need help. :::

Complete the migration

Once you migrate all of the styling, remove unnecessary @mui/styles by uninstalling the package.

With npm:

npm uninstall @mui/styles

With yarn:

yarn remove @mui/styles

:::warning @emotion/styled is a peer dependency of @mui/material. You must keep it in your dependencies even if you never explicitly use it. :::