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 6a340d7
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -128,30 +128,34 @@ 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()` function:

```diff
import Card from '@mui/material/Card';

function App() {
return (
<Card
sx={(theme) => ({
- sx={(theme) => ({
- backgroundColor: theme.palette.mode === 'dark' ? '#000' : '#fff',
- '&:hover': {
- backgroundColor: theme.palette.mode === 'dark' ? '#333' : '#f5f5f5',
- },
+ backgroundColor: '#fff',
+ '&:hover': {
+ backgroundColor: '#f5f5f5',
+ ...theme.applyStyles('dark', {
+ backgroundColor: '#333',
+ }),
- })}
+ sx={(theme) => ([
+ {
+ backgroundColor: '#fff'
+ '&:hover': {
+ backgroundColor: '#f5f5f5',
+ },
+ },
+ ...theme.applyStyles('dark', {
+ theme.applyStyles('dark', {
+ backgroundColor: '#000',
+ '&:hover': {
+ backgroundColor: '#333',
+ },
+ }),
})}
+ ])}
/>
);
}
Expand Down
46 changes: 21 additions & 25 deletions docs/data/material/customization/css-theme-variables/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,36 +48,28 @@ 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:

```js
import Card from '@mui/material/Card';

<Card
sx={(theme) => ({
backgroundColor: theme.vars.palette.background.default,
...theme.applyStyles('dark', {
sx={(theme) => [
{
backgroundColor: theme.vars.palette.background.default,
},
theme.applyStyles('dark', {
boxShadow: 'none', // remove the box shadow in dark mode
}),
})}
]}
/>;
```

:::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 +86,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 +255,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/)

```
```
119 changes: 88 additions & 31 deletions docs/data/material/customization/dark-mode/dark-mode.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,20 +186,22 @@ With the `styled` function:
```jsx
import { styled } from '@mui/material/styles';

const MyComponent = styled('div')(({ theme }) => ({
color: '#fff',
backgroundColor: theme.palette.primary.main,
...theme.applyStyles('dark', {
const MyComponent = styled('div')(({ theme }) => [
{
color: '#fff',
backgroundColor: theme.palette.primary.main,
'&:hover': {
boxShadow: theme.shadows[3],
backgroundColor: theme.palette.primary.dark,
},
},
theme.applyStyles('dark', {
backgroundColor: theme.palette.secondary.main,
}),
'&:hover': {
boxShadow: theme.shadows[3],
backgroundColor: theme.palette.primary.dark,
...theme.applyStyles('dark', {
'&:hover': {
backgroundColor: theme.palette.secondary.dark,
}),
},
}));
},
}),
]);
```

With the `sx` prop:
Expand All @@ -208,19 +210,19 @@ With the `sx` prop:
import Button from '@mui/material/Button';

<Button
sx={[
(theme) => ({
sx={(theme) => [
{
color: '#fff',
backgroundColor: theme.palette.primary.main,
...theme.applyStyles('dark', {
backgroundColor: theme.palette.secondary.main,
}),
'&:hover': {
boxShadow: theme.shadows[3],
backgroundColor: theme.palette.primary.dark,
...theme.applyStyles('dark', {
backgroundColor: theme.palette.secondary.dark,
}),
},
},
theme.applyStyles('dark', {
backgroundColor: theme.palette.secondary.main,
'&:hover': {
backgroundColor: theme.palette.secondary.dark,
},
}),
]}
Expand All @@ -229,6 +231,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 +310,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

0 comments on commit 6a340d7

Please sign in to comment.