sayandcode
sayandcode

Reputation: 3204

When should I use style instead of sx prop in Material-UI?

The style and sx prop in MUI components pretty much do the same thing. The sx prop offers a few shorthand syntaxes, and allows you to access the theme object. But apart from that, they seem identical. When are you supposed to use one over the other?

Upvotes: 44

Views: 34124

Answers (2)

sayandcode
sayandcode

Reputation: 3204

To really understand which one to use, we need to understand what's happening under the hood. Material UI uses emotion(, or whatever styling engine you chose manually), in order to style its components. On the surface, the following two might seem to be doing the same thing:

<Box sx={{ height:'50px', width:'25px' }}/>
<div style={{ height:'50px', width:'25px' }}/>

Both render divs with the required height and width, to the DOM. But for the div, the styles are applied as inline styles, whereas the Box applies the styles in the form of a class, to the div element. The class definition itself, is stored in the head tag, which you can inspect, to see the following CSS class declaration with emotion Css class applied to div

This is all well and fine, as long as we're declaring the styles only once. But stuff really goes crazy when you add dynamic styling. Perhaps there is a state variable controlling the height of your div.

function CustomComponent(){
  const [computedHeight,setComputedHeight]=useState();

  useEffect(()=>{
    window.addEventListener('resize',()=>setComputedHeight(window.innerWidth/2))
  },[]);

  return (
    <Box sx={{ height:computedHeight, width:'25px'}}/>
    <div style={{ height:computedHeight, width:'25px'}}/>
  )

This is a common scenario, where some external variable(the width of the browser window for eg.) determines some property of your component. What happens is every time this state changes into a new value, MUI creates a new class, sets it as the class for the Box, and adds the definition to the <head> tag of your website, as a brand new <style> tag. So in very little time, the head tag fills up with hundreds of style tags, which is clearly undesirable.

However, in the case of your div tag, the styles are located inline. So no matter if the value changes once, or a hundred times, there is only one definition of the style, and it exists on the element itself. No need to worry about it.

EDIT 1:

MUI creates a new style tag only for a style that hasn't been used before. To illustrate, if your sx prop dynamically changes the color between 'red' and 'blue' like this,

sx={{
  color: dynamicValue ? 'red' : 'blue',
}}

MUI will only create two tags(for the two possible values of color), no matter how many times you change the value of dynamicValue. MUI will just use the old style tags.

Note on Pseudo selectors: Another thing to note is that inline styles cannot make use of pseudo elements(like ::after, or ::before), or pseudo classes(like :hover, :focus etc.), as inline styles directly affect the current element. You would have to employ a workaround like css variables in order to change the styles on pseudo elements/classes.

TLDR; Put your dynamic styles(the ones that change based on some variable) in the style prop, and put all the static styles in the sx prop.

Upvotes: 55

Sandeep Amarnath
Sandeep Amarnath

Reputation: 6917

style vs sx in MUI 5

Sandbox Link

sx prop works only on MUI components like Grid, Box and so on, whereas style prop works on both MUI components and HTML like elements (JSX) such as span, article,h1 and so on.

sx prop is very helpful when compared to style prop in some cases as explained below. There might be many differences between them but these are the 3 key differences I have noticed and you might encounter them often.

  • Defining Media queries
  • Nesting styles
  • Making use of theme parameter (to get palette) inside sx object which we can't do in style like this - color: (theme) => theme.palette.primary.main

1. Defining Media queries

One difference between style and sx which is most popular is, defining media queries based on the Material UI theme.

How would you deal with media queries in style prop? You can use your own breakpoints and do it the way you do in CSS for sure, but you cannot use Material UI breakpoints.

This is where sx prop comes in handy where you can define media queries and other MUI provided properties to alter your styles.

Example


import { Typography, createTheme, ThemeProvider } from '@mui/material'

let theme = createTheme()

function Demo() {
  const stylePropCSS = {
    backgroundColor: 'lightblue',

    /* theme prop is not understood here,
       so this breakpoint will not work,
       and text will not turn into orange */

    [theme.breakpoints.down('xl')]: {
      backgroundColor: 'orange',
    },
  }

  /*   theme prop is understood here. 
     breakpoints can be applied here based on MUI theme
  */
  const sxPropCSS = {
    backgroundColor: 'lightgreen',
    [theme.breakpoints.up('xs')]: {
      backgroundColor: 'orange',
    },
  }

  return (
    <ThemeProvider theme={theme}>
      {/* style prop */}
      <Typography style={stylePropCSS}>
        This text will <b>NOT TURN</b> orange as 
        I am using style prop and MUI 'theme' is not understood
      </Typography>

      <br />
      {/* sx prop */}
      <Typography sx={sxPropCSS}>
         This text will <b>TURN</b> into orange as 
         I am using sx prop and MUI 'theme' is understood
      </Typography>
    </ThemeProvider>
  )
}

export default Demo

2. Nesting styles and using theme inside sx prop

You can nest the styles when using sx prop, but can't do this when using style prop.

With sx prop

<Box sx={styles.post}>
  <Typography variant="h4">This is the title</Typography>
</Box>

Box is a div of background black, and I need h4 to be yellow OR MUI primary color. With this requirement, I can nest my styles when I use sx prop like this where I place h4 inside post and define sx only on Box

const styles = {
  post: {
    backgroundColor: 'black',

    // nesting h4 inside post

    h4: {
      // color:'yellow' // OR
      color: (theme) => theme.palette.primary.main,

      /* I cannot use theme inside style object. Since I am going 
to apply styles.post to sx prop,I could make use of theme 
object here as an argument */

    },
  },
}

With style prop

<Box style={styles.post}>
  <Typography variant="h4" style={style.heading}>
    This is the title
  </Typography>
</Box>

const styles = {
  post: {
    backgroundColor: 'black',
  },
  // I can't nest the heading inside post, so defining it outside post
  heading: {
    color: 'yellow',
    // color: (theme) => theme.palette.primary.main, // THIS WON'T WORK with style prop
  },
}

Edit modern-hooks-8wftwx

Upvotes: 14

Related Questions