Reputation: 23553
I already have a styleguide that I'm trying to implement in Material UI. I can see the Button's color prop takes these options:
| 'default'
| 'inherit'
| 'primary'
| 'secondary'
However I need an additional one:
| 'default'
| 'inherit'
| 'primary'
| 'secondary'
| 'tertiary'
Can you create a new color in Material UI that works with the general theming system? Or is this not really how it's supposed to be used?
Upvotes: 19
Views: 10601
Reputation: 80976
UPDATE - This answer was written for v4 of Material-UI. v5 supports custom colors directly and I have added a v5 example at the end.
Though Material-UI does not support this directly in v4, you can wrap Button
in your own custom component to add this functionality.
The code below uses a copy of the styles for textPrimary, outlinedPrimary, and containedPrimary but replaces "primary" with "tertiary".
import * as React from "react";
import Button from "@material-ui/core/Button";
import { makeStyles } from "@material-ui/core/styles";
import clsx from "clsx";
import { fade } from "@material-ui/core/styles/colorManipulator";
const useStyles = makeStyles(theme => ({
textTertiary: {
color: theme.palette.tertiary.main,
"&:hover": {
backgroundColor: fade(
theme.palette.tertiary.main,
theme.palette.action.hoverOpacity
),
// Reset on touch devices, it doesn't add specificity
"@media (hover: none)": {
backgroundColor: "transparent"
}
}
},
outlinedTertiary: {
color: theme.palette.tertiary.main,
border: `1px solid ${fade(theme.palette.tertiary.main, 0.5)}`,
"&:hover": {
border: `1px solid ${theme.palette.tertiary.main}`,
backgroundColor: fade(
theme.palette.tertiary.main,
theme.palette.action.hoverOpacity
),
// Reset on touch devices, it doesn't add specificity
"@media (hover: none)": {
backgroundColor: "transparent"
}
}
},
containedTertiary: {
color: theme.palette.tertiary.contrastText,
backgroundColor: theme.palette.tertiary.main,
"&:hover": {
backgroundColor: theme.palette.tertiary.dark,
// Reset on touch devices, it doesn't add specificity
"@media (hover: none)": {
backgroundColor: theme.palette.tertiary.main
}
}
}
}));
const CustomButton = React.forwardRef(function CustomButton(
{ variant = "text", color, className, ...other },
ref
) {
const classes = useStyles();
return (
<Button
{...other}
variant={variant}
color={color === "tertiary" ? "primary" : color}
className={clsx(className, {
[classes[`${variant}Tertiary`]]: color === "tertiary"
})}
ref={ref}
/>
);
});
export default CustomButton;
Then this CustomButton
component can be used instead of Button
:
import React from "react";
import {
makeStyles,
createMuiTheme,
ThemeProvider
} from "@material-ui/core/styles";
import Button from "./CustomButton";
import lime from "@material-ui/core/colors/lime";
const useStyles = makeStyles(theme => ({
root: {
"& > *": {
margin: theme.spacing(1)
}
}
}));
const theme = createMuiTheme({
palette: {
tertiary: lime
}
});
// This is a step that Material-UI automatically does for the standard palette colors.
theme.palette.tertiary = theme.palette.augmentColor(theme.palette.tertiary);
export default function ContainedButtons() {
const classes = useStyles();
return (
<ThemeProvider theme={theme}>
<div className={classes.root}>
<Button variant="contained">Default</Button>
<Button variant="contained" color="primary">
Primary
</Button>
<Button variant="contained" color="secondary">
Secondary
</Button>
<br />
<Button variant="contained" color="tertiary">
Tertiary
</Button>
<Button color="tertiary">Tertiary text</Button>
<Button variant="outlined" color="tertiary">
Tertiary outlined
</Button>
</div>
</ThemeProvider>
);
}
In v5, the custom button is not necessary. All you need to do is create the theme appropriately:
import React from "react";
import { styled, createTheme, ThemeProvider } from "@material-ui/core/styles";
import Button from "@material-ui/core/Button";
import { lime } from "@material-ui/core/colors";
const defaultTheme = createTheme();
const theme = createTheme({
palette: {
// augmentColor is a step that Material-UI automatically does for the standard palette colors.
tertiary: defaultTheme.palette.augmentColor({
color: { main: lime[500] },
name: "tertiary"
})
}
});
const StyledDiv = styled("div")(({ theme }) => ({
"& > *.MuiButton-root": {
margin: theme.spacing(1)
}
}));
export default function ContainedButtons() {
return (
<ThemeProvider theme={theme}>
<StyledDiv>
<Button variant="contained">Default</Button>
<Button variant="contained" color="primary">
Primary
</Button>
<Button variant="contained" color="secondary">
Secondary
</Button>
<br />
<Button variant="contained" color="tertiary">
Tertiary
</Button>
<Button color="tertiary">Tertiary text</Button>
<Button variant="outlined" color="tertiary">
Tertiary outlined
</Button>
</StyledDiv>
</ThemeProvider>
);
}
Upvotes: 15
Reputation: 1430
Taken from material UI's color palette docs, https://material-ui.com/customization/palette/
A color intention is a mapping of a palette color to a given intention within your application. The theme exposes the following palette colors (accessible under theme.palette.):
primary - used to represent primary interface elements for a user. It's the color displayed most frequently across your app's screens and components.
secondary - used to represent secondary interface elements for a user. It provides more ways to accent and distinguish your product. Having it is optional.
error - used to represent interface elements that the user should be made aware of.
warning - used to represent potentially dangerous actions or important messages.
info - used to present information to the user that is neutral and not necessarily important.
success - used to indicate the successful completion of an action that user triggered. If you want to learn more about color, you can check out the color section.
So you could probably look into reassigning either of the warn/success/info/error buttons. Generally i would keep the error and warn colors both as red, so the warn palette would be free to reassign for me.
Upvotes: 0