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

[docs] Revise "Component theming" and "How to customize" guides #31997

Merged
merged 24 commits into from
Apr 12, 2022
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
25b712c
initial commit
danilo-leal Mar 22, 2022
100e7a3
iteration
danilo-leal Mar 23, 2022
974ea77
general revision
danilo-leal Mar 26, 2022
b5307a1
component theming revision
danilo-leal Mar 26, 2022
f29a278
Jun's review
danilo-leal Mar 28, 2022
5f2bb54
Sam's first batch of reviews
danilo-leal Mar 30, 2022
273cd2a
Jun's review
danilo-leal Mar 30, 2022
e3b4ce1
trimming inspiration
danilo-leal Mar 30, 2022
832c3ec
Sam's second batch of reviews
danilo-leal Mar 30, 2022
15e12f0
remove excerpt about Link's color prop
danilo-leal Mar 30, 2022
24b4bb2
Jun's review: update code snippet
danilo-leal Mar 30, 2022
c72125e
Sam's review
danilo-leal Apr 1, 2022
260faa1
clarifying about specificity
danilo-leal Apr 6, 2022
9fd751e
Olivier's review on using CSS jargon
danilo-leal Apr 7, 2022
6ffc1c3
reordering content on "Overriding nested component styles", Olivier's…
danilo-leal Apr 7, 2022
b44e391
tackle dev tool blurriness
danilo-leal Apr 7, 2022
bda05ff
expand on using the experimental sx prop
danilo-leal Apr 7, 2022
5c0bc5d
line break for better review
danilo-leal Apr 7, 2022
08070da
explain why sx prop alone is stable but inside the theme is experimental
danilo-leal Apr 7, 2022
1429338
Sam's review
danilo-leal Apr 7, 2022
9cf2a44
Merge branch 'master' of https://github.com/mui/material-ui into how-…
danilo-leal Apr 8, 2022
af44cf2
Sam's review
danilo-leal Apr 8, 2022
36436d4
small final tweaks
danilo-leal Apr 12, 2022
ef3c447
yarn docs:typescript:formatted
danilo-leal Apr 12, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
111 changes: 46 additions & 65 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,17 @@ 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.
danilo-leal marked this conversation as resolved.
Show resolved Hide resolved
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.
For consistency with native elements, Material UI 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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think I fully understand the answer to this question. Here's what I gather:

  • pseudo-classes have a high level of specificity
  • MUI's state classes also have a high level of specificity - possibly more than CSS pseudo-classes?
  • this is a good thing because it makes it simple to target individual components using these classes

Is that correct?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • pseudo-classes have a high level of specificity ✅
  • MUI's state classes also have a high level of specificity possibly more than CSS pseudo-classes? they have the same as pseudo states, see https://codepen.io/mnajdova/pen/mdpwxyY
  • this is a good thing because it makes it simple to target individual components component's state using these classes

danilo-leal marked this conversation as resolved.
Show resolved Hide resolved

#### 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 +115,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 +129,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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
> ⚠️ Note that if you are using TypeScript you will need to update the prop's types of the new component.
> ⚠️ Note that if you are using TypeScript you will need to update the prop types of the new component.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like we should move this back right before the demo showing how it should be altered in TypeScript.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before or after? Haven't altered its position, its in the same spot as in the current version.


{{"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 +165,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
@@ -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 preset values for each of its props by default.
To change these default values, use the `defaultProps` key exposed in the theme's `components` key:

```js
const theme = createTheme({
Expand All @@ -27,7 +27,8 @@ To override lab component styles with TypeScript, check [this page](/material-ui

## 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_, since we released after the v5 stable launch, when used directly inside the theme object.
danilo-leal marked this conversation as resolved.
Show resolved Hide resolved

danilo-leal marked this conversation as resolved.
Show resolved Hide resolved
{{"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