Skip to content

Commit

Permalink
Improve applyStyles docs
Browse files Browse the repository at this point in the history
  • Loading branch information
DiegoAndai committed Dec 5, 2024
1 parent 9057a52 commit c68a51b
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ For SSR (server-side rendering) applications, Material UI can not detected user

To prevent the issue, you need to ensure that there is no usage of `theme.palette.mode === 'dark'` in your code base.

If you have such a condition, replace it with the [`theme.applyStyles()`](#appling-dark-styles) function:
If you have such a condition, replace it with the [`theme.applyStyles()`](/material-ui/customization/css-theme-variables/usage/#applying-dark-styles) function:

```diff
import Card from '@mui/material/Card';
Expand Down
38 changes: 16 additions & 22 deletions docs/data/material/customization/css-theme-variables/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ If you want to be able to manually toggle modes, see the guide to [toggling dark

## Applying dark styles

To customize styles for dark mode, use `theme.applyStyles()` function.
This utility function will return the right selector.
To customize styles for dark mode, use the [`theme.applyStyles()` function](/material-ui/customization/dark-mode/#api).
This function returns an object which key is the mode selector and value is the styles object.

The example below shows how to customize the Card component for dark mode:

Expand All @@ -60,24 +60,14 @@ import Card from '@mui/material/Card';
sx={(theme) => ({
backgroundColor: theme.vars.palette.background.default,
...theme.applyStyles('dark', {
boxShadow: 'none', // remove the box shadow in dark mode
backgroundColor: 'white',
}),
})}
/>;
```

:::warning
Do not use `theme.palette.mode` to switch between light and dark styles—this produces an [unwanted flickering effect](/material-ui/customization/dark-mode/#dark-mode-flicker).

```js
<Card
sx={{
// 🚫 this will cause flickering
backgroundColor: theme.palette.mode === 'dark' ? '' : '',
}}
/>
```

Do not use `theme.palette.mode` to switch between light and dark styles—this produces an [unwanted flickering effect](/material-ui/customization/css-theme-variables/configuration/#preventing-ssr-flickering).
:::

## Using theme variables
Expand All @@ -94,17 +84,17 @@ This `vars` object mirrors the structure of a serializable theme, with each valu
}));
```

For **TypeScript**, the typings are not enabled by default.
Follow the [TypeScript setup](#typescript) to enable the typings.
For **TypeScript**, the typings are not enabled by default.
Follow the [TypeScript setup](#typescript) to enable the typings.

:::success
If the components need to render outside of the `CssVarsProvider`, add fallback to the theme object.
:::success
If the components need to render outside of the `CssVarsProvider`, add fallback to the theme object.

```js
backgroundColor: (theme.vars || theme).palette.primary.main;
```
```js
backgroundColor: (theme.vars || theme).palette.primary.main;
```

:::
:::

- **Native CSS**: if you can't access the theme object, for example in a pure CSS file, you can use [`var()`](https://developer.mozilla.org/en-US/docs/Web/CSS/var) directly:

Expand Down Expand Up @@ -263,3 +253,7 @@ declare module '@mui/material/styles' {
## Next steps

If you need to support system preference and manual selection, check out the [advanced configuration](/material-ui/customization/css-theme-variables/configuration/)

```
```
77 changes: 66 additions & 11 deletions docs/data/material/customization/dark-mode/dark-mode.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,72 @@ import Button from '@mui/material/Button';
</Button>;
```

### API

`theme.applyStyles(mode, styles) => CSSObject`

Apply styles for a specific mode.

#### Arguments

- `mode` (`'light' | 'dark'`) - The mode for which the styles should be applied.
- `styles` (`CSSObject`) - An object which contains the styles to be applied for the specified mode.

#### Returns

A `CSSObject` which key is the mode selector and value is the styles object: `{ [modeSelector]: styles }`.

By default, the `modeSelector` is `'@media (prefers-color-scheme: light)'` for light mode and `'@media (prefers-color-scheme: dark)'` for dark mode.

### Specificity

Styles applied with `theme.applyStyles()` have higher specificity than the styles defined outside of it.
This means that to override styles applied with it (via the `styled` function or `sx` prop), you need to use `theme.applyStyles()` as well:

```jsx
const BaseButton = styled('button')(({ theme }) =>
theme.applyStyles('dark', {
backgroundColor: 'white',
}),
);

const AliceblueButton = styled(BaseButton)({
backgroundColor: 'aliceblue', // In dark mode, backgroundColor will be white as theme.applyStyles() has higher specificity
});

const PinkButton = styled(BaseButton)(({ theme }) =>
theme.applyStyles('dark', {
backgroundColor: 'pink', // In dark mode, backgroundColor will be pink
}),
);
```

### Overriding applyStyles

If you need to override `theme.applyStyles()`, you can do so by providing a custom function.
A case in which you might need to do it is to return a string instead of an object so it can be used inside template literals:

```js
const theme = createTheme({
// ...
applyStyles: function (key: string, styles: any) {
// return a string instead of an object
return `@media (prefers-color-scheme: %{key}) & {${styles}}`;
},
});

// This allows to use theme.applyStyles() inside template literals
const StyledButton = styled('button')`
${theme.applyStyles('dark', `
background: white;
`
)}
`;
```

When overriding `theme.applyStyles()`, you have complete control over its arguments and return value.
Please review the [source code](https://github.com/mui/material-ui/blob/HEAD/packages/mui-system/src/createTheme/applyStyles.ts) to understand how the default implementation works before overriding it.

### Codemod

We provide codemods to migrate your codebase from using `theme.palette.mode` to use `theme.applyStyles()`.
Expand All @@ -242,17 +308,6 @@ npx @mui/codemod@latest v6.0.0/theme-v6 <path/to/theme-file>

> Run `v6.0.0/theme-v6` against the file that contains the custom `styleOverrides`. Ignore this codemod if you don't have a custom theme.
### API

`theme.applyStyles(mode, styles) => CSSObject`

Apply styles for a specific mode.

#### Arguments

- `mode` (`'light' | 'dark'`) - The mode for which the styles should be applied.
- `styles` (`CSSObject`) - An object which contains the styles to be applied for the specified mode.

## Dark mode flicker

### The problem
Expand Down
36 changes: 15 additions & 21 deletions packages/mui-system/src/createTheme/applyStyles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,34 +11,28 @@ export interface ApplyStyles<K extends string> {
* - [CSS theme variables](https://mui.com/material-ui/customization/css-theme-variables/overview/)
* - Zero-runtime engine
*
* Tips: Use an array over object spread and place `theme.applyStyles()` last.
*
* ✅ [{ background: '#e5e5e5' }, theme.applyStyles('dark', { background: '#1c1c1c' })]
*
* 🚫 { background: '#e5e5e5', ...theme.applyStyles('dark', { background: '#1c1c1c' })}
*
* @example
* 1. using with `styled`:
* ```jsx
* const Component = styled('div')(({ theme }) => [
* { background: '#e5e5e5' },
* theme.applyStyles('dark', {
* const Component = styled('div')(({ theme }) => {
* background: '#e5e5e5',
* ...theme.applyStyles('dark', {
* background: '#1c1c1c',
* color: '#fff',
* }),
* ]);
* });
* ```
*
* @example
* 2. using with `sx` prop:
* ```jsx
* <Box sx={theme => [
* { background: '#e5e5e5' },
* theme.applyStyles('dark', {
* background: '#1c1c1c',
* color: '#fff',
* }),
* ]}
* <Box sx={theme => {
* background: '#e5e5e5',
* ...theme.applyStyles('dark', {
* background: '#1c1c1c',
* color: '#fff',
* }),
* }}
* />
* ```
*
Expand All @@ -49,13 +43,13 @@ export interface ApplyStyles<K extends string> {
* components: {
* MuiButton: {
* styleOverrides: {
* root: ({ theme }) => [
* { background: '#e5e5e5' },
* theme.applyStyles('dark', {
* root: ({ theme }) => {
* background: '#e5e5e5',
* ...theme.applyStyles('dark', {
* background: '#1c1c1c',
* color: '#fff',
* }),
* ],
* },
* },
* }
* }
Expand Down

0 comments on commit c68a51b

Please sign in to comment.