Natsuko Izuki
Natsuko Izuki

Reputation: 533

What is the alternative of makeStyles for Material UI v.5

I just started using Material UI version 5. Originally to use my custom theme's styles, I would use makestyles, but it seems that does not work in v.5. My themes are on their own component, and to import those, I used {createTheme} instead of the old {createMuiTheme}. I have my theme imported into the Parent component as usual and have it set up as <ThemeProvider theme{theme}></ThemeProvider>.

Now, on my other component, I again was trying to use useStyles, but it was not working because it is not used in version 5. I am having a hard time trying to figure out how to convert it so that it can be used in version 5. Here is some of the unfinished code I was working on:

const useStyles = makeStyles((theme) => ({
    logo: {
        height: "8em",
        marginLeft: "0.2em",
    },
    tabContainer: {
        marginLeft: "auto",
    },
    tab: {
        ...theme.typography.tab,
        minWidth: 10,
        marginRight: "50px",
        opacity: 1,
        "&hover": {
            color: theme.palette.common.purple,
            textDecoration:"none",
        },
    },
}));

export default function Navigation(props) {
    const classes = useStyles();

    const [value, setValue] = useState(0);

    const handleChange = (e, value) => {
        setValue(value);
    };
    const refreshPage = () => {
        window.location.reload();
    };
    
    useEffect(() => {
        switch (window.location.pathname) {
            case "/":
                if (value !== 0) {
                    setValue(0);
                }
                break;
                default:
                break;
        }
    }, [value]);


    return (
      <React.Fragment>
        <ElevationScroll>
          <AppBar
            position="relative"
            style={{
              borderBottom: "2px solid black",
            }}
          >
            <Toolbar disableGutters>
                <img src={logo} alt="nasa logo" className={classes.logo}/>
                <Typography variant="h1" style={{ textAlign: "center" }}>
                  Nasa<br></br>Photos
                </Typography>
                <Tabs
                  value={value}
                  onChange={handleChange}
                  className={classes.tabContainer}
                  indicatorColor="primary"
                >
                  <Tab
                    className={classes.tab}
                    component={Link}
                    onClick={refreshPage}
                    to="/"
                    label="Home"
                  />
                </Tabs>
            </Toolbar>
          </AppBar>
        </ElevationScroll>
      </React.Fragment>
    );
}

I have read about the xs property and I have also heard of the styled() through Material UI's documentation, but I am having a hard time applying it to the code that I have written and would like a push in the right direction.

So to edit what I had earlier, I am going to also add my Theme.js file as well. I thought that this has been done correctly, but again it isn't reading my tab nor my palette.

import {createTheme} from "@mui/material/styles";

const pink = "#FFC0CB";
const lightblue = "#ADD8E6";
const purple = "#800080";
const black = "#000000";

const theme = createTheme({
    palette: {
        common: {
            pink: pink,
            lightblue: lightblue,
            purple: purple,
            black: black
        },
        primary: {
            main: pink,
            mainGradient: "linear-gradient(to left, purple, pink)",
        },
        secondary: {
            main: lightblue,
            mainGradient: "linear-gradient(to right, lightblue, pink)"
        },
    },
    typography: {
        tab: {
            fontFamily:"Orbitron",
            textTransform: "none",
            fontSize: "2.5rem",
            color: black,
        },
        h1: {
            fontFamily: "Orbitron",
            fontSize: "2.5em"
        },
        h2: {
            fontFamily: "Orbitron",
            fontSize: "2.5em"
        },
        subtitle1: {
            fontFamily: "Orbitron"
        },
        subtitle2: {
            fontFamily: "Orbitron",
            fontSize: "1.5rem"
        },
        buttons: {
            fontFamily: "Orbitron",
            textTransform: "none"
        },
    },
});

export default theme

I have imported my theme into my App.js file which is my top level file, I will include that here just in case something has been done wrong with that:

import React,{useState} from "react";
import PicOfDay from "./Components/PictureOfDay";
import Navigation from "./Components/Navigation";
import {
  Typography,
} from "@mui/material";
import {ThemeProvider} from '@mui/material/styles'
import theme from "../src/ui/Theme";
import {BrowserRouter as Router} from "react-router-dom";

function App(props) {
  const [date, setDate] = useState(new Date());
  return (
    <ThemeProvider theme={theme}>
      <Router>
        <Navigation date={date} setDate={setDate} />
        <Typography
          variant="h1"
          style={{fontSize: "5rem", textAlign: "center", marginTop:"2rem"}}
          >
            Astronomy Picture of the Day
        </Typography>  
        {/* <PicOfDay date={date} /> */}
      </Router>
    </ThemeProvider>
  );
}

export default App;

I did look at some documentation a couple of you sent me, and I was looking at the troubleshooting part where it said "[Types] Property "palette", "spacing" does not exist on type 'DefaultTheme'" because makeStyles is exported differently and it does not know about Theme. There seems to be a snipet to put in a typescript project (which I am not running, I am using javascript) and there was a section to add a ts file to my javascript and put the snippet it recommended, which I tried, but am I missing something because it did not do anything and I am not sure if I need to put something in my App.js file in order for it to read that?

Upvotes: 42

Views: 67150

Answers (9)

Acheme Paul
Acheme Paul

Reputation: 1275

You can use the recommended sx or the styled API from @mui/system. But if you like separating CSS similar to the "old" makeStyles, you can use Typescript Record type which will still give CSS typing. Here is an example:

const classes: Record<string, React.CSSProperties> = {
    modal: {
      display: 'flex',
      padding: 1,
      alignItems: 'center',
      justifyContent: 'center',
    },
    paper: {
      width: 700,
      backgroundColor: 'white',
      borderRadius: '10px',
      padding: '15px 20px',
      display: 'flex',
      flexDirection: 'column',
      justifyContent: 'center',
      alignItems: 'center',
      textAlign: 'center',
    },
  };

Then you can use it in your component like so:

<Modal
      open={open}
      onClose={handleClose}
      aria-labelledby="parent-modal-title"
      aria-describedby="parent-modal-description"
      sx={classes.modal}
    >
      <Box sx={classes.paper}>
        <p>Hello world </p>
      </Box>
    </Modal>

Upvotes: 0

Alshafaraz
Alshafaraz

Reputation: 1

an example of how to create theme using mui v5.. I am 2 yrs late to answer this lolz... Was facing similar issue so found this method... leaving it here for someone else :)

import { makeStyles,createTheme, ThemeProvider, StyledEngineProvider } from '@mui/material/styles';

const theme = createTheme({
    palette: {
        mode: 'light',
        primary: {
            main: '#004586',
        },
        secondary: {
            main: '#99002A',
        },
    },
    props: {
        MuiOutlinedInput: {},
    },
});

const useStyles = makeStyles((theme) => ({
    root: {
        '& .MuiTypography-h4 ': {
            paddingLeft: '6px !important',
        },
        '& .MuiTypography-h5 ': {
            paddingLeft: '6px !important',
        },
        '& .MuiTextField-root': {
            margin: theme.spacing(1),
        },
        '& .MuiFormControl-root': {
            margin: theme.spacing(1),
            marginTop: theme.spacing(1),
            minWidth: '275px',
            maxWidth: '275px',
        },
        '& .MuiTableCell-head': {
            fontWeight: '700',
        },
        '& .MuiFormControl-fullWidth': {
            maxWidth: '100% !important',
        },

        '& .small-input.MuiFormControl-root': {
            minWidth: '100px',
            width: '100px',
        },
        '& .small-input.MuiFormControl-root input': {
            textAlign: 'center',
        },
        '& .med-input.MuiFormControl-root': {
            minWidth: '125px',
            width: '125px',
        },
        '& .med-input.MuiFormControl-root input': {
            textAlign: 'center',
        },
        '& .small-label.MuiFormControl-root': {
            minWidth: '90px',
            width: '90px',
        },
        '& .small-label.MuiFormControl-root input': {
            textAlign: 'center',
            paddingLeft: 0,
            paddingRight: 0,
        },
        '& .med-label.MuiFormControl-root': {
            minWidth: '110px',
            width: '110px',
        },
        '& .med-label.MuiFormControl-root input': {
            textAlign: 'center',
            paddingLeft: 0,
            paddingRight: 0,
        },
        '& .small-select.MuiFormControl-root': {
            minWidth: '150px',
            width: '150px',
        },
        '& .med-select.MuiFormControl-root': {
            minWidth: '225px',
            width: '225px',
        },
        '& .MuiTypography-h5': {
            marginTop: theme.spacing(2),
            color: '#004586',
        },
        '& .MuiTypography-h4': {
            marginTop: theme.spacing(2),
            color: '#004586',
        },
        '& .MuiInputLabel-formControl': {
            backgroundColor: '#FAFAFA',
            paddingLeft: '8px',
            paddingRight: '8px',
        },
        '& .MuiPaper-root .MuiInputLabel-formControl': {
            backgroundColor: '#FFFFFF',
            paddingLeft: '8px',
            paddingRight: '8px',
        },
        '& .MuiTypography-root': {
            padding: '10px',
            paddingLeft: '16px',
            paddingRight: '16px',
        },
        '& .MuiDivider-root': {
            marginTop: '20px',
        },
        '& .MuiOutlinedInput-root.Mui-disabled .MuiOutlinedInput-notchedOutline': {
            border: 'none',
        },
        '& .MuiInputBase-input.Mui-disabled': {
            color: 'rgba(0, 0, 0, 0.87)',
        },
        '& .MuiButtonBase-root': {
            cursor: 'pointer !important',
        },
    },
}));

Upvotes: 0

John Franke
John Franke

Reputation: 1535

I made a near drop-in replacement without having to install any libraries. You may need to tweak a few things like padding, margin, and border-radius to be px values. Also, follow patterns using the new SX prop to override existing styles. This sped up our transition greatly.

https://gist.github.com/jottenlips/c96b3023f8512ba49edab440d3326b17

// typescript
import { SxProps } from '@mui/material'
import { useMemo } from 'react'

type TStylesFunction = (
  props?: any,
) => Record<string, React.CSSProperties | SxProps>
type TStyles = Record<string, React.CSSProperties | SxProps>

export const makeStylesHook = (styles: TStylesFunction | TStyles) => {
  // useStyles returned like deprecated MUI makeStyles
  const useStyles =
    typeof styles === 'function'
      ? (props?: any) => {
          return useMemo(() => styles(props), [props])
        }
      : (_props?: any) => {
          return useMemo(() => styles, [])
        }
  return useStyles
}
  
// use
// const useStyles = makeStylesHook((props) => ({ box: { backgroundColor: "green"}}))
//...
// const Component = () => { 
//   const classes = useStyles()
//   return <Box sx={classes.box} />
// }

Upvotes: 0

Mauro Bilotti
Mauro Bilotti

Reputation: 6262

Assuming that you need to use the theme in your styles, This:

const useStyles = makeStyles((theme) => (
 root : {
   background: theme.palette.primary.main,
 }));

Becomes this:

import { SxProps, Theme, useTheme } from "@mui/material/styles";

const useStyles = (theme: Theme): { [key: string]: SxProps } => ({
   root : {
     background: theme.palette.primary.main,
   }
})

Upvotes: 0

Ali Sajadian
Ali Sajadian

Reputation: 43

@mui/styles is not compatible with React.StrictMode or React 18.

it's recommanded to use the sx props

import * as React from 'react';
import { Box } from '@mui/system';

export default function BasicUsage() {
  return (
    <Box
      component= 'div'
      sx={{
        color: 'darkslategray',
        backgroundColor: 'aliceblue',
        padding: 8,
        borderRadius: 4,
      }}
    >
      Styled div
    </Box>
  );
}

or

you can use styled() function from @mui/system package or @mui/material/styles package, if no theme be created, the difference is in the default theme used in these packages.

import * as React from 'react'; 
import { styled } from '@mui/system';
     
const MyComponent = styled('div')({   
  color: 'darkslategray',  
  backgroundColor: 'aliceblue',   
  padding: 8,   
  borderRadius: 4, 
});
     
export default function BasicUsage() {   
  return <MyComponent>Styled div</MyComponent>;
}

Upvotes: 2

Goksel Yesiller
Goksel Yesiller

Reputation: 31

import * as React from 'react';
import { StyledEngineProvider } from '@mui/material/styles';

export default function GlobalCssPriority() {
  return (
    <StyledEngineProvider injectFirst>
      {/* Your component tree. Now you can override MUI's styles. */}
    </StyledEngineProvider>
  );
}

You need to use provider on main file to get default styles first.
Visit here Material UI injections!

Upvotes: 1

AbHisheK ThaKur
AbHisheK ThaKur

Reputation: 81

so what i understood from this question is that you want to add custom classes to the material-ui components. and makestyles is giving you error about theme.. you can resolve this by providing default theme to makestyles. you can use ThemeProvider to do that.. all you've to do is create a default theme with createTheme() then use that in ThemeProvider to pass it to all components in tree below ThemeProvider.. just use ThemeProvider to wrap your root component and that will provide default theme to each makeStyles that are currently in use..

import { makeStyles } from '@mui/styles';
import { createTheme, ThemeProvider } from '@mui/material/styles';

const theme = createTheme();

 const useStyles = makeStyles((theme) => (
 root : {
   background: theme.palette.primary.main,
 }));

 function Component() {
   const classes = useStyles();
   return <div className={classes.root} />
 }

 // In the root of your app
 function App(props) {

 return <ThemeProvider theme={theme}><Component {...props} /></ThemeProvider>;
 }

Upvotes: -1

Reza
Reza

Reputation: 543

Based on documentation:

@mui/styles is the legacy styling solution for MUI. It is deprecated in v5. It depends on JSS as a styling solution, which is not used in the @mui/material anymore.

You can use the-sx-prop or styled

Upvotes: 12

Fred Nguyen
Fred Nguyen

Reputation: 325

You can still use the makeStyles utils as what you're using, but in material v5 if you love to do it you need to install one more package @mui/styles and

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

https://mui.com/guides/migration-v4/#mui-material-styles

The makeStyles JSS utility is no longer exported from @mui/material/styles. You can use @mui/styles/makeStyles instead.

Also, you need to add tab and purple to createTheme if you need them

const theme = createTheme({
  typography: {
    tab: {
      fontSize: 20,
    },
  },
  palette: {
    common: {
      purple: 'purple',
    },
  },
})

Upvotes: 15

Related Questions