Themes
Customize Material-UI with your theme. You can change the colors, the typography and much more.
The theme specifies the color of the components, darkness of the surfaces, level of shadow, appropriate opacity of ink elements, etc.
Themes let you apply a consistent tone to your app. It allows you to customize all design aspects of your project in order to meet the specific needs of your business or brand.
To promote greater consistency between apps, light and dark theme types are available to choose from. By default, components use the light theme type.
Theme provider
If you wish to customize the theme, you need to use the MuiThemeProvider
component in order to inject a theme into your application.
However, this is optional; Material-UI components come with a default theme.
MuiThemeProvider
relies on the context feature of React to pass the theme down to the components,
so you need to make sure that MuiThemeProvider
is a parent of the components you are trying to customize.
You can learn more about this in the API section.
Theme configuration variables
Changing the theme configuration variables is the most effective way to match Material-UI to your needs. The following sections cover the most important theme variables:
Palette
Intentions
A color intention is a mapping of a palette to a given intention within your application.
The theme exposes the following color intentions:
- primary - used to represent primary interface elements for a user.
- secondary - used to represent secondary interface elements for a user.
- error - used to represent interface elements that the user should be made aware of.
The default palette uses the shades prefixed with A
(A200
, etc.) for the secondary intention,
and the un-prefixed shades for the other intentions.
If you want to learn more about color, you can check out the color section.
Custom palette
You may override the default palette values by including a palette
object as part of your theme.
If any of the palette.primary
,
palette.secondary
or
palette.error
'intention' objects are provided, they will replace the defaults.
The intention value can either be a color object, or an object with one or more of the following keys:
interface PaletteIntention {
light?: string;
main: string;
dark?: string;
contrastText?: string;
};
Using a color object
The simplest way to customize an intention is to import one or more of the provided colors and apply them to a palette intention:
import { createMuiTheme } from '@material-ui/core/styles';
import blue from '@material-ui/core/colors/blue';
const theme = createMuiTheme({
palette: {
primary: blue,
},
});
If the intention key receives a color object as in the example above, the following mapping is used to populate the required keys:
palette: {
primary: {
light: palette.primary[300],
main: palette.primary[500],
dark: palette.primary[700],
contrastText: getContrastText(palette.primary[500]),
},
secondary: {
light: palette.secondary.A200,
main: palette.secondary.A400,
dark: palette.secondary.A700,
contrastText: getContrastText(palette.secondary.A400),
},
error: {
light: palette.error[300],
main: palette.error[500],
dark: palette.error[700],
contrastText: getContrastText(palette.error[500]),
},
},
This example illustrates how you could recreate the default palette values:
import { createMuiTheme } from '@material-ui/core/styles';
import indigo from '@material-ui/core/colors/indigo';
import pink from '@material-ui/core/colors/pink';
import red from '@material-ui/core/colors/red';
// All the following keys are optional.
// We try our best to provide a great default value.
const theme = createMuiTheme({
palette: {
primary: indigo,
secondary: pink,
error: red,
// Used by `getContrastText()` to maximize the contrast between the background and
// the text.
contrastThreshold: 3,
// Used to shift a color's luminance by approximately
// two indexes within its tonal palette.
// E.g., shift from Red 500 to Red 300 or Red 700.
tonalOffset: 0.2,
},
});
Providing the colors directly
If you wish to provide more customized colors, you can either create your own color object, or directly supply colors to some or all of the intention's keys:
import { createMuiTheme } from '@material-ui/core/styles';
const theme = createMuiTheme({
palette: {
primary: {
// light: will be calculated from palette.primary.main,
main: '#ff4400',
// dark: will be calculated from palette.primary.main,
// contrastText: will be calculated to contrast with palette.primary.main
},
secondary: {
light: '#0066ff',
main: '#0044ff',
// dark: will be calculated from palette.secondary.main,
contrastText: '#ffcc00',
},
// error: will use the default color
},
});
As in the example above, if the intention object contains custom colors using any of the
main
, light
, dark
or contrastText
keys, these map as follows:
If the
dark
and / orlight
keys are omitted, their value(s) will be calculated frommain
, according to thetonalOffset
value.If
contrastText
is omitted, its value will be calculated to contrast withmain
, according to thecontrastThreshold
value.
Both the tonalOffset
and contrastThreshold
values may be customized as needed.
A higher value for tonalOffset
will make calculated values for light
lighter, and dark
darker.
A higher value for contrastThreshold
increases the point at which a background color is considered
light, and given a dark contrastText
.
Note that contrastThreshold
follows a non-linear curve.
Example
Color tool
Need inspiration? The Material Design team has built an awesome palette configuration tool to help you.
Type (light /dark theme)
You can make the theme dark by setting type
to dark
.
While it's only a single property value change, internally it modifies the value of the following keys:
palette.text
palette.divider
palette.background
palette.action
const theme = createMuiTheme({
palette: {
type: 'dark',
},
});
Typography
Too many type sizes and styles at once can spoil any layout. The theme provides a limited set of type sizes that work well together along with the layout grid. These sizes are used across the components.
Have a look at the following example regarding changing the default values, such as the font family. If you want to learn more about typography, you can check out the typography section.
Typography - Font family
const theme = createMuiTheme({
typography: {
// Use the system font instead of the default Roboto font.
fontFamily: [
'-apple-system',
'BlinkMacSystemFont',
'"Segoe UI"',
'Roboto',
'"Helvetica Neue"',
'Arial',
'sans-serif',
'"Apple Color Emoji"',
'"Segoe UI Emoji"',
'"Segoe UI Symbol"',
].join(','),
},
});
Typography - Font size
Material-UI uses rem
units for the font size.
The browser <html>
element default font size is 16px
, but browsers have an option to change this value,
so rem
units allow us to accommodate the user's settings, resulting in a much better user experience.
Users change font size settings for all kinds of reasons, from poor eyesight to choosing optimum settings
for devices that can be vastly different in size and viewing distance.
To change the font-size of Material-UI you can provide a fontSize
property.
The default value is 14px
.
const theme = createMuiTheme({
typography: {
// In Japanese the characters are usually larger.
fontSize: 12,
},
});
The computed font size by the browser follows this mathematical equation:
Typography - HTML font size
You might want to change the <html>
element default font size. For instance, when using the 10px simplification.
We provide a htmlFontSize
theme property for this use case.
It's telling Material-UI what's the font-size on the <html>
element is.
It's used to adjust the rem
value so the calculated font-size always match the specification.
const theme = createMuiTheme({
typography: {
// Tell Material-UI what's the font-size on the html element is.
htmlFontSize: 10,
},
});
html {
font-size: 62.5%; /* 62.5% of 16px = 10px */
}
You need to apply the above CSS on the html element of this page to see the below demo rendered correctly
Other variables
In addition to the palette, dark and light types, and typography, the theme normalizes implementation by providing many more default values, such as breakpoints, shadows, transitions, etc. You can check out the default theme section to view the default theme in full.
Custom variables
When using Material-UI's styling solution with your own components, you can also take advantage of the theme. It can be convenient to add additional variables to the theme so you can use them everywhere. For instance:
Customizing all instances of a component type
CSS
When the configuration variables aren't powerful enough, you can take advantage of the
overrides
key of the theme
to potentially change every single style injected by Material-UI into the DOM.
That's a really powerful feature.
const theme = createMuiTheme({
overrides: {
MuiButton: { // Name of the component ⚛️ / style sheet
text: { // Name of the rule
color: 'white', // Some CSS
},
},
},
});
The list of these customization points for each component is documented under the Component API section. For instance, you can have a look at the Button. Alternatively, you can always have a look at the implementation.
Properties
You can also apply properties on all the instances of a component type.
We expose a props
key in the theme
for this use case.
const theme = createMuiTheme({
props: {
// Name of the component ⚛️
MuiButtonBase: {
// The properties to apply
disableRipple: true, // No more ripple, on the whole application 💣!
},
},
});
Accessing the theme in a component
You might need to access the theme variables inside your React components.
Let's say you want to display the value of the primary color, you can use the withTheme()
higher-order component to do so. Here is an example:
Nesting the theme
The theming solution is very flexible, as you can nest multiple theme providers. This can be really useful when dealing with different area of your application that have distinct appearance from each other.
The inner theme will override the outer theme. You can extend the outer theme by providing a function:
A note on performance
The performance implications of nesting the MuiThemeProvider
component are linked to JSS's work behind the scenes.
The main point to understand is that we cache the injected CSS with the following tuple (styles, theme)
.
theme
: If you provide a new theme at each render, a new CSS object will be computed and injected. Both for UI consistency and performance, it's better to render a limited number of theme objects.styles
: The larger the styles object is, the more work is needed.
API
MuiThemeProvider
This component takes a theme
property, and makes the theme
available down the React tree thanks to React context.
It should preferably be used at the root of your component tree.
You can see the full properties API in this dedicated page.
Examples
import React from 'react';
import { render } from 'react-dom';
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles';
import Root from './Root';
const theme = createMuiTheme();
function App() {
return (
<MuiThemeProvider theme={theme}>
<Root />
</MuiThemeProvider>
);
}
render(<App />, document.querySelector('#app'));
createMuiTheme(options) => theme
Generate a theme base on the options received.
Arguments
options
(Object): Takes an incomplete theme object and adds the missing parts.
Returns
theme
(Object): A complete, ready to use theme object.
Examples
import { createMuiTheme } from '@material-ui/core/styles';
import purple from '@material-ui/core/colors/purple';
import green from '@material-ui/core/colors/green';
const theme = createMuiTheme({
palette: {
primary: purple,
secondary: green,
},
status: {
danger: 'orange',
},
});
withTheme()(Component) => Component
Provide the theme
object as a property of the input component so it can be used
in the render method.
Arguments
Component
: The component that will be wrapped.
Returns
Component
: The new component created.
Examples
import { withTheme } from '@material-ui/core/styles';
function MyComponent(props) {
return <div>{props.theme.direction}</div>;
}
export default withTheme()(MyComponent);