What is the best approach to customize classes in material-ui with makeStyles and useStyles?

Imagine a scenario where there is a component responsible for rendering a button with a red background and yellow text color. A Parent component utilizes this child component but specifies that it wants the background color to be green while keeping the text color as yellow.

withStyles

No issues when utilizing the traditional withStyles method.

import React from "react";
import { withStyles } from "@material-ui/core/styles";
import { Button } from "@material-ui/core";

const parentStyles = {
  root: {
    background: "green"
  }
};
const childStyles = {
  root: {
    background: "red"
  },
  label: {
    color: "yellow"
  }
};

const ChildWithStyles = withStyles(childStyles)(({ classes }) => {
  return <Button classes={classes}>Button in Child withStyles</Button>;
});

const ParentWithStyles = withStyles(parentStyles)(({ classes }) => {
  return <ChildWithStyles classes={classes} />;
});


export default ParentWithStyles;

https://i.sstatic.net/UL3Dr.png

https://codesandbox.io/s/passing-classes-using-withstyles-w17xs?file=/demo.tsx

makeStyles/useStyles

Let's experiment with the makeStyles/useStyles approach and refer to the guide Overriding styles - classes prop on material-ui.com.

import React from "react";
import { makeStyles } from "@material-ui/styles";
import { Button } from "@material-ui/core";

const parentStyles = {
  root: {
    background: "green"
  }
};
const childStyles = {
  root: {
    background: "red"
  },
  label: {
    color: "yellow"
  }
};

// The useStyles variant does NOT allow me to override classes
const useParentStyles = makeStyles(parentStyles);
const useChildStyles = makeStyles(childStyles);

const ChildUseStyles = ({ classes: classesOverride }) => {
  const classes = useChildStyles({ classes: classesOverride });
  return (
    <>
      <Button classes={classes}>Button1 in Child useStyles</Button>
      <Button classes={classesOverride}>Button2 in Child useStyles</Button>
    </>
  );
};
const AnotherChildUseStyles = props => {
  const classes = useChildStyles(props);
  return (
    <>
      <Button classes={classes}>Button3 in Child useStyles</Button>
    </>
  );
};
const ParentUseStyles = () => {
  const classes = useParentStyles();
  return <>
    <ChildUseStyles classes={classes} />
    <AnotherChildUseStyles classes={classes} />
  </>;
};

export default ParentUseStyles;

https://i.sstatic.net/OVkxQ.png

https://codesandbox.io/s/passing-classes-using-usestyles-6x5hf?file=/demo.tsx

It appears challenging to achieve the desired effect I had with withStyles using the classes overriding method (particularly making sense to me previously).

  • What am I misunderstanding about passing classes for overriding purposes using useStyles?
  • How should I approach it differently?
  • If my current approach is incorrect, why is material-ui still issuing a warning when the parent contains styles not found in the child?
  • Is there documentation available for migrating from the old withStyles approach to the new one?

By the way, I am aware of this solution, but it seems cumbersome when dealing with numerous overrides.

const useStyles = makeStyles({
  root: {
    backgroundColor: 'red',
    color: props => props.color,
  },
});

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

Answer №1

withStyles serves primarily as a wrapper for makeStyles / useStyles to create higher-order components with minimal functionality.

If you're not achieving the desired results, it could be due to the order in which styles are executed.

Instead of:

const useParentStyles = makeStyles(parentStyles);
const useChildStyles = makeStyles(childStyles);

You should reorder it like this:

const useChildStyles = makeStyles(childStyles);
const useParentStyles = makeStyles(parentStyles);

The sequence of calling makeStyles influences the stylesheet order in the <head>, impacting style specificity where later styles take precedence over earlier ones. Unlike using withStyles, multiple useStyles calls can lead to unpredictable ordering that may not prioritize overrides correctly.

It's essential to understand that you're not just passing overrides but merging classes together. For instance, if

childClasses.root === 'child_root_1'
and
parentClasses.root === 'parent_root_1'
, the merged result would be
mergedClasses.root === 'child_root_1 parent_root_1'
. This means any element with the className set to mergedClasses.root will receive both CSS rules, ultimately determined by their specificity.

For more insights, check these related answers:

  • Material UI v4 makeStyles exported from a single file doesn't retain styles on refresh
  • Exploring the internal workings of "makeStyles" in React Material-UI?

Answer №2

When working with Material-ui 4.11.x and utilizing the makeStyles function to create styles, make sure to encapsulate the styles within createStyles. This approach ensures that the style defined will take precedence over any default styling.

const useStyles = makeStyles((theme: Theme) =>
  createStyles({
    backdrop: {
      zIndex: theme.zIndex.drawer + 1,
      color: '#fff',
    },
  }),
);

To observe the impact, you can experiment by removing the createStyles and comparing the results. Source code retrieved from: https://material-ui.com/components/backdrop/

Answer №3

To change the styling of a class using withStyles, consider the following method which can be useful for customizing CSS classes.

If you wish to modify a class named ".myclass" that includes "position: absolute;":

import { withStyles } from '@material-ui/styles';

const styles = {
    "@global": {
      ".myClass": {
        position: "relative", 
      }
   }
};

const TestComponent = (props) =>  (
     <>
         <SomeComponent {...props}>
     </>
);    

export default withStyles(styles)(TestComponent);

By implementing this code, you can override the styling of .myClass as declared in <SomeComponent/> to be "position: relative;".

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Encountering a persistent issue with POST http://localhost:3001/subscribe resulting in a 500 (Internal Server Error

My tech stack includes React for the client-side, NodeJS for the backend, and MySQL for the database. I am working on implementing an email subscription service where users can input their email addresses on the client side and have them stored in the data ...

Why can't the file upload button locate its CSS styles?

Check out this jFiddle demonstrating the issue. Some of the Angular code may appear broken in the example, but that's just due to it being pasted into jFiddle; it's not an actual problem I'm facing. The CSS styles aren't working on the ...

Is there a way to customize the pagination layout of primeNG paginator in an Angular project

I've been struggling to customize the primeNG paginator in my Angular application. Specifically, I am trying to style the dropdown that lets users select the number of data entries. Despite my efforts to figure it out, I have not been successful in st ...

Why is this text appearing twice on my screen?

When I run the code in my React app and check the console in Chrome, I notice that the response.data[0] is being printed twice. What could be causing this duplication? const fetchData = async () => { return await axios.get(URL) .then((respon ...

Using React and TypeScript to enable file uploads

Seeking assistance in creating a basic single select upload component. When I click a button that contains a hidden input field, the file dialog opens and allows me to choose a file. The placeholder then changes to display the selected file name along with ...

The JSX element 'body' appears to be missing its closing tag

I'm currently in the process of developing a landing page using react.js. This particular page is designed for users who are not yet signed up to create an account if they wish to do so. Unfortunately, I'm encountering some errors, one of which p ...

Why does the <select> dropdown flash when I select it?

Currently utilizing Angular 1.3 and Bootstrap 3.3.x CSS without the JS functionality. There is also an interesting animated GIF embedded within. <div class="form-group"> <div class="col-lg-3"> <label clas ...

Wordpress Debacle: Bootstrap Columns Clash

Currently, I am in the process of designing a unique theme. In my code, I have implemented a condition that generates an additional div with the class "row" after every three posts or columns are created. Everything seems to be working smoothly, except f ...

How can I implement server-side rendering for SVG graphics with React?

Currently working on a project utilizing both Highcharts and React where server side rendering for the SVG generated is crucial. Any recommendations on how to achieve this in order to obtain a static rendered page with images in png/jpg format? The browser ...

Display a page with sections that have opacity applied, identified by the hashtag #section, and utilize JavaScript to automatically scroll to the top of

Check out my app at . I'm working on overriding the scroll bar behavior in CSS to keep the entire app visible, including the logo, header, and controls, as users navigate through different sections. However, I seem to be having trouble with the CSS as ...

Using namespaces in Rails to encapsulate CSS styles

Is there a way to add namespaces to CSS within a Rails project? I have two pre-defined CSS files and two application layouts. I want the first layout to use one CSS file, and the second layout to use the other. However, both CSS files have styles for the ...

Ways to verify that component props are being successfully passed

Imagine having a component like this function RankDialog(props: any) { const { visible = true, setVisible } = props; return ( <Dialog visible={visible} className="rank-dialog" scrollBoxClassName="rank-scroll-box& ...

Leverage flex columns in Bootstrap 4.0 for advanced layout options

Hey, I need some assistance to set up columns in my code. Here's the current code snippet: <div class="container-fluid h-100"> <div class="row h-100"> <div class="flex-column h-100">side menu</div> <div ...

Present two logos on either side of a navigation bar with Bootstrap in between

I am facing an issue with the display of my two logos. One logo is supposed to be in the right corner and the other in the left, but the right logo is not appearing correctly. <header class="navbar navbar-inverse navbar-fixed-top bs-docs-nav" role="ban ...

What are the drawbacks of utilizing CSS word-wrap across all elements on a website?

Is there a downside to utilizing the CSS property word-wrap:break-word in this manner? body { word-wrap: break-word; } The definitions for the values of this property are as follows: normal: Breaks words only at allowed breakpoints break-word: Perm ...

ESLint's feature experimentalObjectRestSpread not being applied with expected behavior

ESLint is showing an unexpected token error, specifically error Parsing error: Unexpected token .., and I'm struggling to identify the root cause. In my .eslintrc.js file, I have: module.exports = { extends: "devmountain/react-config" , rul ...

What is the process for immediately changing the background color of an input field as soon as text is entered?

I am encountering an issue with the code snippet provided below. My goal is to change the background color of an input field as soon as I start typing something into it. The scenario involves 4 input fields where if the submit button is clicked and any f ...

The size of the cursor varies depending on the line it's placed on

I have a content editable div where three lines are separated by BR tags. When I click on the second line, the cursor becomes bigger than that in the first line. .content { line-height: 35px; } <div class="content" contenteditable="true"> ...

Using JavaScript to generate a <style> element and accessing the cssRules

After spending countless hours trying to solve this problem, I'm hoping that my question isn't too foolish. This is a continuation of a previous question about creating a style tag with JavaScript on Stack Overflow. The solutions provided by Tom ...

Issue encountered with NextJS where the post request utilizing Bcrypt is not being recognized

In the process of developing a basic login feature using nextJS, I have successfully managed to save new usernames and encrypted passwords from the registration page. The login functionality is intended to be similar, but requires comparing the password st ...