Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can we add new property for color in palette in MuiTheme #14185

Closed
kushal-tech opened this issue Jan 15, 2019 · 15 comments
Closed

Can we add new property for color in palette in MuiTheme #14185

kushal-tech opened this issue Jan 15, 2019 · 15 comments
Labels
new feature New feature or request priority: important This change can make a difference
Milestone

Comments

@kushal-tech
Copy link

Like MuiTheme already provided a way to override colors of 3 property

  • Primary

  • Secondary

  • error

This is the below way to change the colors of existing properties.

palette: {
  primary: {
    main: palette.primary[500],
  },
  secondary: {
    main: palette.secondary.A400,
  },
  error: {
    main: palette.error[500],
  },
},

What If we need to define new property for color like

palette: {
  primary: {
    main: palette.primary[500],
  },
  secondary: {
    main: palette.secondary.A400,
  },
  error: {
    main: palette.error[500],
  },

>   success : {
>     main : "#bac778"
>   }

},

Is that possible ?

@oliviertassinari
Copy link
Member

@kushaljain03 Yes, you can:

const theme = createMuiTheme({
  palette: {
    success: {
      main : "#bac778",
    },
  },
})

@kushal-tech
Copy link
Author

kushal-tech commented Jan 15, 2019

Yes I can but I cannot use it like
<Button color="success">Login</Button>

It gives warning about to use only primary default secondary

@oliviertassinari
Copy link
Member

No, you can't use the success color property directly. You need to create a wrapping component to use the theme values.
Going forward, I wish we can make it work. We have recently added the support for style functions. If the performance are good enough. We can imagine changing the implementation.

@eps1lon
Copy link
Member

eps1lon commented Jan 15, 2019

Adding additional properties is not explicitly documented. At least I couldn't find it. I think we can add another section that also includes how one would make this work with TypeScript.

Actually: https://material-ui.com/customization/themes/#custom-variables for JS and https://material-ui.com/guides/typescript/#customization-of-theme with additional info for TS.

@oliviertassinari oliviertassinari added new feature New feature or request priority: important This change can make a difference labels Jan 15, 2019
@davidcalhoun
Copy link
Contributor

Color styling has been one of the major difficulties when using this library. For instance, a simple use case where you have three buttons side-by-side, all different colors. Trying to style this with themes is really limiting and unintuitive. From what I can tell this is only possible to implement with the first two buttons using one theme, then the third button using a different (nested) theme:

  • button 1 (theme A, color=primary)
  • button 2 (theme A, color=secondary)
  • button 3 (theme B, color=primary)

But this is a weird way to break things up logically, because in this app all of these colors should be under one theme.

Another option is to avoid themes for this entirely, but then this seems to give up the nice benefits of having the contrastText helpers and such.

@oliviertassinari
Copy link
Member

oliviertassinari commented Mar 2, 2019

@davidcalhoun Yes, you are right, this issue is about extending the Button implementation so people can just do:

const theme = createMuiTheme({
  palette: {
    success: {
      main : "#bac778",
    },
  },
})

then have a working:

<Button color="success" />

implementation.

The best solution right now is to add the color in the theme, then to create a wrapping component:

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

const Button = withStyles(theme => ({
  root: props =>
    props.color === "success" && props.variant === "contained"
      ? {
          color: theme.palette.success.contrastText,
          backgroundColor: theme.palette.success.main,
          "&:hover": {
            backgroundColor: theme.palette.success.dark,
            // Reset on touch devices, it doesn't add specificity
            "@media (hover: none)": {
              backgroundColor: theme.palette.success.main
            }
          }
        }
      : {}
}))(MuiButton);

const theme = createMuiTheme();

theme.palette.success = theme.palette.augmentColor({
  main: "#689f38"
});

function Theming() {
  return (
    <ThemeProvider theme={theme}>
      <Button variant="contained" color="primary">
        primary
      </Button>
      <Button variant="contained" color="success">
        success
      </Button>
    </ThemeProvider>
  );
}

export default Theming;

https://codesandbox.io/s/7zmw6ox8m1

capture d ecran 2019-03-02 a 19 13 54


By the way, we are planing on extending the color to primary | secondary | success | warning | error/danger? | info. Would that help in your case?

@oliviertassinari
Copy link
Member

oliviertassinari commented Mar 2, 2019

If you don't care about the warnings, you can do 🤷‍♂️:

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

const theme = createMuiTheme();
theme.palette.success = theme.palette.augmentColor({
  main: "#689f38"
});

const isSuccess = style => props =>
  props.color === "success" && props.variant === "contained" ? style : {};

theme.overrides = {
  MuiButton: {
    root: {
      color: isSuccess(theme.palette.success.contrastText),
      backgroundColor: isSuccess(theme.palette.success.main),
      "&:hover": {
        backgroundColor: isSuccess(theme.palette.success.dark)
      }
    }
  }
};

function Theming() {
  return (
    <ThemeProvider theme={theme}>
      <Button variant="contained" color="primary">
        primary
      </Button>
      <Button variant="contained" color="success">
        success
      </Button>
    </ThemeProvider>
  );
}

export default Theming;

https://codesandbox.io/s/r15rlnlznq

@davidcalhoun
Copy link
Contributor

Thanks for the great examples! That helps. For sure, having other color names outside of just "primary" and "secondary" helps a lot, but I'm not sure if it solves my use case.

In my case I'm trying to use color themes for a dropdown button I'm creating with three states:

  1. Draft (a greyish background)
  2. In Progress (bluish background)
  3. Completed (greenish color)

It would be great to be able to define these in a theme somehow, but these states don't necessarily map onto semantic names (primary and secondary work fine for two of the three colors though!). I like defining them in the theme and then being able to rely on the theme to automatically figure out derived colors (text state based on contrast, hover state colors, etc).

I'm guessing the philosophy is different (or maybe it's a performance concern?), but I would kind of prefer being able to define custom color names inside the theme that wouldn't necessarily be semantic or whatnot, just practical. For the cases above, I'd like to define some colors inside the theme called grey, blue, and green.

I especially like the second example, but I want to avoid anything that generates warnings! For this particular use case, I think I'll just avoid using themes for now and look for other styling options.

@eps1lon
Copy link
Member

eps1lon commented Mar 4, 2019

@davidcalhoun This is something I'm experimenting locally. The material design guidelines already define a color and the "contrast" color (or "on" color in material speak).

The idea is that you can add any color in the theme and either let us figure out what a good "on"-color would be or let you define that too. The component should then take care of the rest i.e. given a color name figure out what color to choose for background, text or iconography.

States like hover, disabled, focused etc are currently handled via opacity in the material guidelines. Would be interesting to explore possible APIs to make this customizable too e.g. let the user define a theme wide function with the following signature: (Color, State) => Color.

@eps1lon eps1lon added this to the v4 milestone Mar 4, 2019
@kaitlynbrown

This comment has been minimized.

@mbrookes

This comment has been minimized.

@kaitlynbrown

This comment has been minimized.

@eps1lon
Copy link
Member

eps1lon commented Apr 9, 2019

Closing this in favor of #13875. You can already add custom colors to the palette. Just not use them in color props of our components.

@acapro
Copy link

acapro commented Oct 27, 2020

For a typescript implementation you can do something like this. Using props in the styles are avoided to improve JSS performance. (This avoids generating unique classes for every button and works great in large lists, etc...)

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

import Button, { ButtonProps } from "@material-ui/core/Button";
import capitalize from "lodash/capitalize";

export type ColorTypes =
  | "primary"
  | "secondary"
  | "error"
  | "success"
  | "warning"
  | "default"
  | "inherit"
  | "info";

export type ColoredButtonProps = { color: ColorTypes } & Omit<
  ButtonProps,
  "color"
>;

const useStyles = makeStyles<Theme>(theme =>
  createStyles({
    outlinedSuccess: {
      borderColor: theme.palette.success.main,
      color: theme.palette.success.main
    },
    outlinedError: {
      borderColor: theme.palette.error.main,
      color: theme.palette.error.main
    },
    outlinedWarning: {
      borderColor: theme.palette.warning.main,
      color: theme.palette.warning.main
    },
    outlinedInfo: {
      borderColor: theme.palette.info.main,
      color: theme.palette.info.main
    },
    containedSuccess: {
      backgroundColor: theme.palette.success.main,
      color: theme.palette.success.contrastText,
      "&:hover": {
        backgroundColor: theme.palette.success.dark
      }
    },
    containedError: {
      backgroundColor: theme.palette.error.main,
      color: theme.palette.error.contrastText,
      "&:hover": {
        backgroundColor: theme.palette.error.dark
      }
    },
    containedWarning: {
      backgroundColor: theme.palette.warning.main,
      color: theme.palette.warning.contrastText,
      "&:hover": {
        backgroundColor: theme.palette.warning.dark
      }
    },
    containedInfo: {
      backgroundColor: theme.palette.info.main,
      color: theme.palette.info.contrastText,
      "&:hover": {
        backgroundColor: theme.palette.info.dark
      }
    }
  })
);

const ColoredButton: React.FC<ColoredButtonProps> = ({
  children,
  color,
  ...props
}) => {
  const classes = useStyles();
  const className = classes?.[`${props.variant}${capitalize(color)}`];
  const colorProp =
    ["default", "inherit", "primary", "secondary"].indexOf(color) > -1
      ? (color as "default" | "inherit" | "primary" | "secondary")
      : undefined;

  return (
    <Button {...props} color={colorProp} className={className}>
      {children}
    </Button>
  );
};

ColoredButton.displayName = "ColoredButton";

export default ColoredButton;

@nazanin-bayati
Copy link

For a typescript implementation and mui 5, you can act like this.
Example of new color in the palette file:

import { colors } from "@mui/material",

const common = {
  infromation: {
    warnning: '#CFDD4A',
  }
}

type.ts will be like this:

import Palette from "@mui/material/styles/createPalette";

declare module '@mui/material/styles' {
  interface Palette {
    infromation?: {
      warnning?: string
    }
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
new feature New feature or request priority: important This change can make a difference
Projects
None yet
Development

No branches or pull requests

8 participants