Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How reliable are MUI Global Class names in JSS?

I have code like this:

const formControlStyles = {
  root: {
    '&:hover .MuiFormLabel-root': {

     }
  }
}

Is it safe to use the class name in theme overrides to access other components? Additionally, is there a JSS way of nesting styles from other components?

like image 698
Gasim Avatar asked Mar 17 '20 11:03

Gasim


People also ask

What is JSS MUI?

JSS plugins JSS uses plugins to extend its core, allowing you to cherry-pick the features you need, and only pay the performance overhead for what you are using. Not all the plugins are available in MUI by default. The following (which is a subset of jss-preset-default) are included: jss-plugin-rule-value-function.

What is material UI withStyles?

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.

How do you use makeStyles in material UI?

In order to use makeStyles function in your application you will need to import it in the component in where you plan to access the css that results from your makeStyles function. This is assuming you have already installed Material Ui in your project. This is in order for react to recognize it as a styles file.

What is MUI theme provider?

MUI provides a ThemeProvider component that provides the theme to all the UI components in the app. This component expects a theme object as its only argument (yep, the custom theme we created earlier!):


1 Answers

UPDATE for v5 This answer was originally written regarding v4 of Material-UI. In v5, the global class names are no longer used by Material-UI to apply the default styles -- the classes used for the default styles have class names generated by Emotion. The global class names are still applied, but they are no longer impacted by nested themes, so in v5 it is completely safe to leverage the global class names for overrides without needing to use the [class*=... syntax mentioned in my original answer below.


It is fairly safe to use global class names, but with one caveat (in v4). If you leverage nested themes, the global class names applied within the nested theme will have an unpredictable suffix (e.g. MuiFormLabel-root-371). This suffixing is necessary, because the default styles associated with a nested theme can be different.

In order to target the class names in a completely safe manner, you can use the *= attribute selector (e.g. [class*="MuiFormLabel-root"]) which checks to see if the element has a class name that contains MuiFormLabel-root rather than needing to match it exactly. You can see this approach used within Material-UI itself here.

So long as you don't intend on using nested themes, it is safe (and much more readable) to use the simpler syntax of matching the global class names exactly. An alternative approach is to specify a JSS class on the nested component and refer to that class using the JSS syntax for referring to another rule in the same stylesheet (e.g. $myFormLabel in my example), but this requires being able to apply that class (e.g. classes.myFormLabel in my example) to the nested component.

Below is an example which demonstrates the issue (and some possible solutions) when using nested themes.

import React from "react";
import {
  ThemeProvider,
  createMuiTheme,
  makeStyles
} from "@material-ui/core/styles";
import FormLabel from "@material-ui/core/FormLabel";

const theme1 = createMuiTheme();
const theme2 = createMuiTheme({
  overrides: {
    MuiFormLabel: {
      root: {
        color: "#00ff00"
      }
    }
  }
});

const useStyles = makeStyles({
  mostlySafe: {
    "&:hover .MuiFormLabel-root": {
      color: "red"
    }
  },
  safeButTediousAndMoreErrorProneSyntax: {
    '&:hover [class*="MuiFormLabel-root"]': {
      color: "purple"
    }
  },
  alternativeApproach: {
    "&:hover $myFormLabel": {
      color: "blue"
    }
  },
  myFormLabel: {}
});
export default function App() {
  const classes = useStyles();
  return (
    <ThemeProvider theme={theme1}>
      <div>
        <div className={classes.mostlySafe}>
          <FormLabel>FormLabel within top-level theme</FormLabel>
        </div>
        <ThemeProvider theme={theme2}>
          <div className={classes.mostlySafe}>
            <FormLabel>
              FormLabel within nested theme (hover styling doesn't work)
            </FormLabel>
          </div>
          <div className={classes.safeButTediousAndMoreErrorProneSyntax}>
            <FormLabel>
              FormLabel within nested theme using safe approach
            </FormLabel>
          </div>
          <div className={classes.alternativeApproach}>
            <FormLabel className={classes.myFormLabel}>
              FormLabel within nested theme without using global class names
            </FormLabel>
          </div>
        </ThemeProvider>
      </div>
    </ThemeProvider>
  );
}

Edit Global class names

like image 159
Ryan Cogswell Avatar answered Oct 02 '22 22:10

Ryan Cogswell