11

Does anyone know how to use multiple CSS classes with MUI 5 SX prop? I created a base class that I want to use with my Box components but use a second class specifically for the text inside of the Box. Applying base class, such as sx={styles.baseBoxStyle} works but sx={styles.baseBoxStyle styles.customBoxFontStyle} returns an error. Full code snippet and sandbox provided below. Any assistance is greatly appreciated!

Sandbox: https://codesandbox.io/s/mui-5-styling-uqt9m?file=/pages/index.js

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

const styles = {
  baseBoxStyle: {
    backgroundColor: "red",
    borderRadius: "20px 20px 20px 20px",
    border: "1px solid black",
    maxWidth: "150px",
    margin: "20px",
    padding: "10px"
  },
  customBoxFontStyle: {
    color: "yellow",
    fontWeight: "bold"
  }
};

export default function Index() {
  return <Box sx={styles.baseBoxStyle styles.customBoxFontStyle}>This is a test</Box>;
}
2

7 Answers 7

15

I had a similar problem and came up with this solution.

  <Box sx={[styles.baseBoxStyle, styles.customBoxFontStyle]}>
    This is a test
  </Box>

https://codesandbox.io/s/sweet-blackwell-oqp9ph?file=/src/App.js:416-517

Sign up to request clarification or add additional context in comments.

1 Comment

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
11

If you want combine 2 calsses, and you get one of them as props you should work like this

const componnent = (styles) => {
 return ( 
  <ListItem
    sx={[
      {
        width: 'auto',
        textDecoration: 'underline',
      },
      ...(Array.isArray(styles) ? styles : [styles]),
    ]}
  /> 
 )
}

You cannot spread sx directly because SxProps (typeof sx) can be an array

Comments

5

For a simple solution, can deconstruct the style objects and compile into one object.

<Box sx={{...styles.baseBoxStyle,...styles.customBoxFontStyle}}>This is a test</Box>

Comments

3

You can try to use classnames as its commonly used library, or you can just make string from these styles that you pass into sx sx={styles.baseBoxStyle+' '+styles.customBoxFontStyle}

4 Comments

I just now tried the suggested on sx prop but it doesn't work as they are objects. codesandbox.io/s/mui-5-styling-uqt9m?file=/pages/index.js
oh sorry, i dont know why i thought, these are classes... but there you can try to combine these two objects: sx={{...styles.baseBoxStyle,...styles.customBoxFontStyle}}
Sorry Wraithy, that doesn't work either.
my apologizes. Your solution does indeed work. I confirmed this after consulting with another React developer who suggested the same. Not sure why it didn't work initially tested but I suspect I neglected to wrap it in additional curly brackets.
3

With the following functions

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

export const withSxProp = (
    sxProp: SxProps<Theme> | undefined,
    other: SxProps<Theme>
): SxProps<Theme> => {
    if (!sxProp) {
        return other;
    } else {
        return mergeSx(sxProp, other);
    }
};

export const mergeSx = (...sxProps: SxProps<Theme>[]): SxProps<Theme> => {
    return sxProps.reduce((prev, currentValue) => {
        return [
            ...(Array.isArray(prev) ? prev : [prev]),
            ...(Array.isArray(currentValue) ? currentValue : [currentValue]),
        ];
    }, [] as SxProps<Theme>);
};

Usage

class MyComponent = (parentSxProp: SxProps<Theme>) => {
    const sxChildDefault = {
       display: "flex"
    }
    const innerSx1 = {
        display: "flex"
    }
    const innerSx2 = {
        flexDirection: "column"
    }
    return <Box
       sx={withSxProp(parentSxProp, sxChildDefault)}
    >
        <Box
            sx={mergeSx(innerSx1, innerSx2)}
        />
    </Box>
}

Comments

2

To build on Aleksander's answer, there is a section about merging sx in MUI official documentation.

import * as React from 'react';
import ListItem from '@mui/material/ListItem';
import FormLabel from '@mui/material/FormLabel';
import { SxProps, Theme } from '@mui/material/styles';

interface ListHeaderProps {
  children: React.ReactNode;
  sx?: SxProps<Theme>;
}

function ListHeader({ sx = [], children }: ListHeaderProps) {
  return (
    <ListItem
      sx={[
        {
          width: 'auto',
          textDecoration: 'underline',
        },
        // You cannot spread `sx` directly because `SxProps` (typeof sx) can be an array.
        ...(Array.isArray(sx) ? sx : [sx]),
      ]}
    >
      <FormLabel sx={{ color: 'inherit' }}>{children}</FormLabel>
    </ListItem>
  );
}

export default function PassingSxProp() {
  return (
    <ListHeader
      sx={(theme) => ({
        color: 'info.main',
        ...theme.typography.overline,
      })}
    >
      Header
    </ListHeader>
  );
}

Comments

0

I think you cant use sx with classes. I have not seen any example in documentation.

4 Comments

In this context I'm referring to JSS as classes, not traditional CSS class. In the example I provided in this post, sx={styles.baseBoxStyle} works without issue.
I see. styles.baseBoxStyle is js object. It pretends just temporary constant. In these cases making a new object by destruction will work. I was confused you try to do similar way as makeStyles does.
I'm migrating from v4 to v5 and because I used makeStyles in v4, which is deprecated in v5, my goal was to not have to reformat all of my styling.
Yeap. I am new to MUI. I have the same problem. All examples I find a references point are made with makeStyles in v4. I can use the legacy method for my works, it works but I am trying to figure out how should styles components in v5 way.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.