Skip to content

Commit

Permalink
[docs] Revise "Component theming" and "How to customize" guides (#31997)
Browse files Browse the repository at this point in the history
Co-authored-by: Siriwat K <siriwatkunaporn@gmail.com>
  • Loading branch information
danilo-leal and siriwatknp committed Apr 12, 2022
1 parent 19c0ad3 commit de11911
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 84 deletions.
112 changes: 46 additions & 66 deletions docs/data/material/customization/how-to-customize/how-to-customize.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,61 +5,55 @@ components: GlobalStyles

# How to customize

<p class="description">You can easily customize the appearance of a MUI component.</p>
<p class="description">Learn how to customize Material UI components by taking advantage of different strategies for specific use cases.</p>

As components can be used in different contexts, there are several approaches to customizing them. Going from the narrowest use-case to the broadest, these are:
Material UI provides several different ways to customize a component's styles. Your specific context will determine which one is ideal. From narrowest to broadest use case, here are the options:

1. [One-off customization](#1-one-off-customization)
1. [Reusable style overrides](#2-reusable-style-overrides)
1. [Dynamic variation](#3-dynamic-variation)
1. [Global theme variation](#4-global-theme-variation)
1. [Global CSS override](#5-global-css-override)

## 1. One-off customization

You might need to change the style of a component for a specific implementation, for which you have the following solutions available:
To change the styles of _one single instance_ of a component, you can use one of the following options:

### Use the `sx` prop
### The `sx` prop

The easiest way to add style overrides for a one-off situation is to use the [`sx` prop](/system/basics/#the-sx-prop) available on all MUI components.
Here is an example:
The [`sx` prop](/system/basics/#the-sx-prop) is the best option for adding style overrides to a single instance of a component in most cases.
It can be used with all Material UI components.

{{"demo": "SxProp.js"}}
{{"demo": "SxProp.js" }}

Next you'll see how you can use global class selectors for accessing slots inside the component. You'll also learn how to easily identify the classes which are available to you for each of the states and slots in the component.
#### Overriding nested component styles

### Overriding nested component styles
To customize a specific part of a component, you can use the class name provided by Material UI inside the `sx` prop. As an example, let's say you want to change the `Slider` component's thumb from a circle to a square.

You can use the browser dev tools to identify the slot for the component you want to override. It can save you a lot of time.
The styles injected into the DOM by MUI rely on class names that [follow a simple pattern](/system/styles/advanced/#class-names):
`[hash]-Mui[Component name]-[name of the slot]`.

⚠️ These class names can't be used as CSS selectors because they are unstable,
however, MUI applies global class names using a consistent convention: `Mui[Component name]-[name of the slot]`.

Let's go back to the above demo. How can you override the slider's thumb?
First, use your browser's dev tools to identify the class for the component slot you want to override.

<img src="/static/images/customization/dev-tools.png" alt="dev-tools" width="406" />
The styles injected into the DOM by Material UI rely on class names that all [follow a standard pattern](/styles/advanced/#class-names):
`[hash]-Mui[Component name]-[name of the slot]`.

In this example, the styles are applied with `.css-ae2u5c-MuiSlider-thumb` so the name of the component is `Slider` and the name of the slot is `thumb`.
In this case, the styles are applied with `.css-ae2u5c-MuiSlider-thumb` but you only really need to target the `.MuiSlider-thumb`, where `Slider` is the component and `thumb` is the slot. Use this class name to write a CSS selector within the `sx` prop (`& .MuiSlider-thumb`), and add your overrides.

You now know that you need to target the `.MuiSlider-thumb` class name for overriding the look of the thumb:
<img src="/static/images/customization/dev-tools.png" alt="dev-tools" width="796" style="margin-bottom: 16px;" />

{{"demo": "DevTools.js"}}

> ⚠️ Note that these class names can't be used as CSS selectors because they are unstable.
### Overriding styles with class names

If you would like to override the styles of the components using classes, you can use the `className` prop available on each component. For overriding the styles of the different parts inside the component, you can use the global classes available for each slot, as described in the previous section.
If you want to override a component's styles using custom classes, you can use the `className` prop, available on each component.
To override the styles of a specific part of the component, use the global classes provided by Material UI, as described in the previous section—[Overriding nested component styles](#overriding-nested-component-styles).

You can find examples of this using different styles libraries in the [Styles library interoperability](/material-ui/guides/interoperability/) guide.
Visit the [Style library interoperability](/guides/interoperability/) guide to find examples of this approach using different styling libraries.

### State classes

The components special states, like _hover_, _focus_, _disabled_ and _selected_, are styled with a higher CSS specificity.
[Specificity is a weight](https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity) that is applied to a given CSS declaration.
States like _hover_, _focus_, _disabled_ and _selected_, are styled with a higher CSS specificity. To customize them, you'll need to **increase specificity**.

In order to override the components' special states, **you need to increase specificity**.
Here is an example with the _disable_ state and the Button component using a pseudo-class (`:disabled`):
Here is an example with the _disable_ state and the `Button` component using a pseudo-class (`:disabled`):

```css
.Button {
Expand All @@ -76,9 +70,9 @@ Here is an example with the _disable_ state and the Button component using a pse
<Button disabled className="Button">
```

Sometimes, you can't use a CSS pseudo-class, as the state doesn't exist in the web specification.
Let's take the MenuItem component and its _selected_ state as an example.
In such cases you can use a MUI equivalent of CSS pseudo-classes - **state classes**.
You can't always use a CSS pseudo-class, as the state doesn't exist in the web specification.
Let's take the `MenuItem` component and its _selected_ state as an example.
In this situation, you can use Material UI's **state classes**, which act just like CSS pseudo-classes.
Target the `.Mui-selected` global class name to customize the special state of the `MenuItem` component:

```css
Expand All @@ -96,15 +90,16 @@ Target the `.Mui-selected` global class name to customize the special state of t
<MenuItem selected className="MenuItem">
```

If you'd like to learn more about this topic, we recommend checking out [the MDN Web Docs on CSS Specificity](https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity).

#### Why do I need to increase specificity to override one component state?

By design, the CSS specification makes the pseudo-classes increase the specificity.
For consistency with native elements, MUI increases the specificity of its custom state classes.
This has one important advantage, it allows you to cherry-pick the state you want to customize.
CSS pseudo-classes have a high level of specificity.
For consistency with native elements, Material UI's state classes have the same level of specificity as CSS pseudo-classes, making it possible to target an individual component's state.

#### What custom state classes are available in MUI?
#### What custom state classes are available in Material UI?

You can rely on the following [global class names](/system/styles/advanced/#with-material-ui-core) generated by MUI:
You can rely on the following [global class names](/styles/advanced/#with-material-ui-core) generated by Material UI:

| State | Global class name |
| :------------ | :------------------ |
Expand All @@ -119,10 +114,10 @@ You can rely on the following [global class names](/system/styles/advanced/#with
| required | `.Mui-required` |
| selected | `.Mui-selected` |

> ⚠️ Never style these state classes' names directly:
> ⚠️ Never apply styles directly to state class names. This will impact all components with unclear side-effects. Always target a state class together with a component.
```css
/* ❌ NOT OK, impact all the components with unclear side-effects */
/* ❌ NOT OK */
.Mui-error {
color: red;
}
Expand All @@ -133,28 +128,23 @@ You can rely on the following [global class names](/system/styles/advanced/#with
}
```

## 2. Reusable style overrides
## 2. Reusable component

If you find that you need the same overrides in multiple places across your application, you can use the [`styled()`](/system/styled/) utility to create a reusable component:
To reuse the same overrides in different locations across your application, create a reusable component using the [`styled()`](/system/styled/) utility:

{{"demo": "StyledCustomization.js", "defaultCodeOpen": true}}

With it, you have access to all of a component's props to dynamically style the component.

## 3. Dynamic variation
### Dynamic overrides

In the previous section, we learned how to override the style of a MUI component.
Now, let's see how we can make these overrides dynamic.
Here are four alternatives; each has its pros and cons.
The `styled()` utility lets you add dynamic styles based on a component's props.
You can do this with **dynamic CSS** or **CSS variables**.

### Dynamic CSS
#### Dynamic CSS

Using the `styled()` utility offers a simple way for adding dynamic styles based on props.
> ⚠️ Note that if you are using TypeScript you will need to update the prop's types of the new component.
{{"demo": "DynamicCSS.js", "defaultCodeOpen": false}}

> ⚠️ Note that if you are using TypeScript you will need to update the prop's types of the new component.
```tsx
import * as React from 'react';
import { styled } from '@mui/material/styles';
Expand All @@ -174,29 +164,19 @@ const StyledSlider = styled(Slider, {
}));
```

### CSS variables
#### CSS variables

{{"demo": "DynamicCSSVariables.js"}}

## 4. Global theme variation

In order to promote consistency between components, and manage the user interface appearance as a whole, MUI provides a mechanism to apply global changes.

Please take a look at the theme's [global overrides page](/material-ui/customization/theme-components/) for more details.

## 5. Global CSS override
## 3. Global theme overrides

Components expose [global class names](/system/styles/advanced/#with-material-ui-core) to enable customization with CSS.

```css
.MuiButton-root {
font-size: 1rem;
}
```
Material UI provides theme tools for managing style consistency between all components across your user interface.
Visit the [Component theming customization](/customization/theme-components/) page for more details.

You can reference the [Styles library interoperability guide](/material-ui/guides/interoperability/) to find examples of this using different styles libraries or plain CSS.
## 4. Global CSS override

If you just want to add some global baseline styles for some of the HTML elements, you can use the `GlobalStyles` component. Here is an example of how you can override styles for the `h1` elements.
To add global baseline styles for some of the HTML elements, use the `GlobalStyles` component.
Here is an example of how you can override styles for the `h1` elements:

{{"demo": "GlobalCssOverride.js", "iframe": true, "height": 100}}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const theme = createTheme({
export default function DefaultProps() {
return (
<ThemeProvider theme={theme}>
<Button>Change default props</Button>
<Button>This button has disabled ripples.</Button>
</ThemeProvider>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const theme = createTheme({
export default function DefaultProps() {
return (
<ThemeProvider theme={theme}>
<Button>Change default props</Button>
<Button>This button has disabled ripples.</Button>
</ThemeProvider>
);
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<ThemeProvider theme={theme}>
<Button>Change default props</Button>
<Button>This button has disabled ripples.</Button>
</ThemeProvider>
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Components

<p class="description">The theme's components key allows you to customize a component without wrapping it in another component. You can change the styles, the default props, and more.</p>
<p class="description">You can customize a component's styles, default props, and more by using its keys inside the theme. This helps to achieve styling consistency across your application.</p>

## Default props

You can change the default of every prop of a MUI component.
A `defaultProps` key is exposed in the theme's `components` key for this use case.
Every Material UI component has default preset values for each of its props.
To change these default values, use the `defaultProps` key exposed in the theme's `components` key:

```js
const theme = createTheme({
Expand All @@ -14,7 +14,7 @@ const theme = createTheme({
MuiButtonBase: {
defaultProps: {
// The props to change the default for.
disableRipple: true, // No more ripple!
disableRipple: true, // No more ripple, on the whole application 💣!
},
},
},
Expand All @@ -23,11 +23,12 @@ const theme = createTheme({

{{"demo": "DefaultProps.js"}}

To override lab component styles with TypeScript, check [this page](/material-ui/about-the-lab/#typescript).
If you're using Typescript and [lab components](/material-ui/about-the-lab/), check [this article to learn how to override their styles](/material-ui/about-the-lab/#typescript).

## Global style overrides

You can use the theme's `styleOverrides` key to potentially change every single style injected by MUI into the DOM.
The theme's `styleOverrides` key makes it possible to potentially change every single style injected by Material UI into the DOM.
This is useful if you want to apply a fully custom design system to Material UI's components.

```js
const theme = createTheme({
Expand All @@ -48,9 +49,25 @@ const theme = createTheme({

{{"demo": "GlobalThemeOverride.js"}}

The list of each component's classes is documented under the **CSS** section of its API page.
Each component is composed of several different parts.
These parts correspond to classes that are available to the component—see the **CSS** section of the component's API page for a detailed list.
You can use these classes inside the `styleOverrides` key to modify the corresponding parts of the component.

To override a lab component's styles with TypeScript, check [this section of the documentation](/material-ui/about-the-lab/#typescript).
```js
const theme = createTheme({
components: {
MuiButton: {
styleOverrides: ({ ownerState }) => ({
...(ownerState.variant === 'contained' &&
ownerState.color === 'primary' && {
backgroundColor: '#202020',
color: '#fff',
}),
}),
},
},
});
```

### Overrides based on props

Expand All @@ -77,17 +94,49 @@ const finalTheme = createTheme({

{{"demo": "GlobalThemeOverrideCallback.js"}}

### Using `sx` (experimental) syntax
### The `sx` syntax (experimental)

The `sx` prop acts as a shortcut for defining custom styles that access the theme object.
This prop lets you write inline styles using a superset of CSS.
Learn more about [the concept behind the `sx` prop](/system/the-sx-prop/) and [how `sx` differs from the `styled` utility](/system/styled/#difference-with-the-sx-prop).

You can use the `sx` prop inside the `styleOverrides` key to modify styles within the theme using shorthand CSS notation.
This is especially handy if you're already using the `sx` prop with your components, because you can use the same syntax in your theme and quickly transfer styles between the two.

> **Note:** The `sx` prop is a stable feature for customizing components in Material UI v5, but it is still considered _experimental_ when used directly inside the theme object.
{{"demo": "GlobalThemeOverrideSx.js", "defaultCodeOpen": false}}

If you are not familiar `sx`, first check out [the concept](/system/the-sx-prop/) and [the difference with the `styled`](/system/styled/#difference-with-the-sx-prop).
```tsx
const finalTheme = createTheme({
components: {
MuiChip: {
styleOverrides: {
root: sx({
px: 1,
py: 0.25,
borderRadius: 1,
}),
label: {
padding: 'initial',
},
icon: sx({
mr: 0.5,
ml: '-2px',
}),
},
},
},
});
```

`sx` is also compatible with theme style overrides if you prefer the shorthand notation.
### Specificity

{{"demo": "GlobalThemeOverrideSx.js"}}
If you use the theming approach to customize the components, you'll still be able to override them using the `sx` prop as it has a higher CSS specificity, even if you're using the experimental `sx` syntax within the theme.

## Adding new component variants
## Creating new component variants

You can use the `variants` key in the theme's `components` section to add new variants to MUI components. These new variants can specify what styles the component should have when specific props are applied.
You can use the `variants` key in the theme's `components` section to create new variants to Material UI components. These new variants can specify what styles the component should have when that specific variant prop value is applied.

The definitions are specified in an array, under the component's name. For each of them a CSS class is added to the HTML `<head>`. The order is important, so make sure that the styles that should win are specified last.

Expand Down
Binary file modified docs/public/static/images/customization/dev-tools.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion docs/src/modules/components/Demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ function useUniqueId(prefix) {
}

const Root = styled('div')(({ theme }) => ({
marginBottom: 40,
marginBottom: 24,
marginLeft: theme.spacing(-2),
marginRight: theme.spacing(-2),
[theme.breakpoints.up('sm')]: {
Expand Down

0 comments on commit de11911

Please sign in to comment.