Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Material-UI Theme Overrides Leveraging Theme Palette Colors

I'm currently customizing a few components using global theme overrides in the hopes of maintaining as much of the integrity of the Material-UI theming engine as possible. I know I could accomplish what I'm trying to do using composition, but I want to see if it's possible to achieve this via overrides.

The Goal

Change the background color of the BottomNavigation component to use the primary color of the current theme, and ensure the label gets a color that is legible on top of that background color.

My Current Approach

const theme = createMuiTheme({
    palette: {
      primary: {
        main: 'rgba(217,102,102,1)'
      }
    },
    overrides: {
        MuiBottomNavigation: {
            root: {
                backgroundColor: 'rgba(217,102,102,1)'
            }
        },
        MuiBottomNavigationAction: {
            wrapper: {
                color: '#fff'
            }
        }
    }
});

This code accomplishes the task and turns the bottom navigation red and the label/icons white. However, I want the flexibility of being able to change the primary color in the palette and have the component update accordingly.

What I'm Trying To Do

const theme = createMuiTheme({
    palette: {
      primary: {
        main: 'rgba(217,102,102,1)'
      }
    },
    overrides: {
        MuiBottomNavigation: {
            root: {
                backgroundColor: 'primary.main'
            }
        },
        MuiBottomNavigationAction: {
            wrapper: {
                color: 'primary.contrastText'
            }
        }
    }
});

In this way I could easily update the primary color and not have to worry about changing every reference to it across my overrides. I realize I could extract the rgba value out into a const and that would accomplish part of my goal, but I don't see how I could access something as useful as contrastText in case I choose a much lighter primary color.

So - does anyone know of a way to reference theme palette colors in a theme override definition? Any help would be greatly appreciated!

like image 992
n-devr Avatar asked Aug 23 '19 17:08

n-devr


2 Answers

There's another approach here. createMuiTheme accepts any number of additional theme objects to be merged together.

With that in mind you could replicate your accepted answer without having two different ThemeProvider. And if you move the theme definition to its own module, it won't be recreated on each render.

import { createMuiTheme } from "@material-ui/core/styles";

const globalTheme = createMuiTheme({
  palette: {
    primary: {
      main: "rgba(217,255,102,1)"
    }
  }
});

const theme = createMuiTheme(
  {
    overrides: {
      MuiButton: {
        root: {
          backgroundColor: globalTheme.palette.primary.main
        },
        label: {
          color: globalTheme.palette.primary.contrastText
        }
      }
    }
  },
  globalTheme
);

export default theme;

I updated the CodeSandBox to reflect this.

like image 150
Nicolás Fantone Avatar answered Nov 13 '22 18:11

Nicolás Fantone


Ill provide two solutions- one is more readable and maintainable, and one has better performance.

  1. The readable and maintainable approach:
    Create nested themes.
    One theme will be for defining the palette, and one theme will be for overrides.
    Because its two themes, you can access the palette theme from overrides theme:

    const globalTheme = createMuiTheme({
      palette: {
        primary: {
          main: 'rgba(217,255,102,1)'
        }
      },
    });
    
    const overridesTheme = createMuiTheme({
      overrides: {
        MuiButton: {
            root: {
                backgroundColor: globalTheme.palette.primary.main,
            },
            label: {
              color:globalTheme.palette.primary.contrastText,
            }
        },
    }
    })
    

    You can refer to this CodeSandbox

    This approach doesn't have good performance, bacause every render a new CSS object will be computed and injected


  1. The better performance approach:
    First you create an Mui theme skeleton, with the palette. After it has been created, you add the styles that rely on the palette (notice how I have to use the spread operator a lot to avoid deleting styles):

    const theme = createMuiTheme({
      palette: {
        primary: {
          main: 'rgba(217,255,102,1)'
        }
      },
    })
    
    theme.overrides = {
      ...theme.overrides,
      MuiButton: {
          ...theme.MuiButton,
          root: {
             ...theme.root,
              backgroundColor: theme.palette.primary.main,
          },
          label: {
            ...theme.label,
            color:theme.palette.primary.contrastText,
          }
      },
    }
    

    You can refer to this CodeSandbox

like image 18
Ido Avatar answered Nov 13 '22 19:11

Ido