Migrate all website pages to use CSS theme variables
See original GitHub issueWe need your help!
Help us migrate the website to start using CSS theme variables!
Progress
If you are interested to contribute, check out the How-to and add your name at the end of the bullet to let us know that you are working on it.
Once you have done the migration, open a PR with the title [website] Migrate xxx page to use CSS theme variables
where “xxx” is the page that you pick.
- Home page (
/) #33545 - Product-Core (
/core/) https://github.com/mui/material-ui/pull/35366 - ⏳ Product-X (
/x/) https://github.com/mui/material-ui/pull/34922 - ⏳ Product-Templates (
/templates/) @EduardoSCosta https://github.com/mui/material-ui/pull/34913 - ⏳ Product-Design-kits (
/design-kits/) @jesrodri https://github.com/mui/material-ui/pull/34920 - ~Product-Toolpad (
/toolpad/)~ this should be done in the Toolpad repo - ⏳ Pricing (
/pricing/) @trizotti https://github.com/mui/material-ui/pull/34917 - ⏳ About us (
/about/) @brianlu2610 https://github.com/mui/material-ui/pull/34919 - ⏳ Careers (
/careers/) @the-mgi https://github.com/mui/material-ui/pull/34908 - Blog posts (
/blog/*) https://github.com/mui/material-ui/pull/34976
How-to
-
go to the page (in
docs/pages/folder) that you want to work on. Let’s takedocs/pages/templates.tsxas an example. -
Replace
BrandingProviderwithBrandingCssVarsProvider-import BrandingProvider from 'docs/src/BrandingProvider'; +import BrandingCssVarsProvider from 'docs/src/BrandingCssVarsProvider'; -<BrandingProvider> +<BrandingCssVarsProvider>Start the development server via
yarn docs:devand goto/templates/, you are likely to encounterWarning: Prop "className" did not match. Server:or something similar. This is because some components in the page is relying on the runtime calculation to change the styles based on the color mode. Those conditions must be fixed as explained in the next step! -
Look at each component imported on the page, e.g.
TemplateHero.tsx, and find the conditional expression like this:<Typography ... color={(theme) => (theme.palette.mode === 'dark' ? 'primary.400' : 'primary.600')} >Then, replace the condition with
theme.applyDarkStyles():-color={(theme) => (theme.palette.mode === 'dark' ? 'primary.400' : 'primary.600')} +sx={theme => ({ + color: 'primary.600', + ...theme.applyDarkStyles({ + color: 'primary.400', + }), +})}- Check out migration scenarios to see other patterns. If you encounter a scenario that is not in the migration patterns, feel free to open a PR and ask for help.
- Read the implementation details about the
theme.applyDarkStyles.
-
Refresh the page, you should not see a warning coming from the
TemplateHero.tsx(you might still see the warning but coming from other components on the page). -
Once you have fixed all the components, open a PR with the title
[website] Migrate xxx page to use CSS theme variablesand tag @siriwatknp as a reviewer.
Migration patterns
Here are some use cases that you might encounter in the migration process.
1. Conditional expression in the prop that’s not sx
Example code:
<Typography color={theme => theme.palette.mode === 'dark' : 'grey.200' : 'grey.700'}>
Migrated code: Move the logic to sx prop:
<Typography
sx={theme => ({
color: 'grey.700',
...theme.applyDarkStyles({
color: 'grey.200',
})
}))
>
2. Usage from theme.palette.*
Example code:
<Typography color={theme => theme.palette.mode === 'dark' : theme.palette.grey[200] : theme.palette.grey[700]}>
Migrated code: attach (theme.vars || theme).*:
<Typography
sx={theme => ({
color: (theme.vars || theme).palette.grey[700],
...theme.applyDarkStyles({
color: (theme.vars || theme).palette.grey[200],
})
}))
>
3. Conditional expression in sx prop
Example code:
<Typography
sx={{
color: theme => theme.palette.mode === 'dark' : 'grey.200' : 'grey.700',
bgcolor: theme => theme.palette.mode === 'dark' : 'grey.500' : 'grey.600',
}}
>
Migrated code: Remove the condition and group into dark styles:
<Typography
sx={theme => ({
color: 'grey.700',
bgcolor: 'grey.600',
// `theme.applyDarkStyles()` must come later
...theme.applyDarkStyles({
color: 'grey.200',
bgcolor: 'grey.500',
})
})}
>
4. Conditional expression in sx prop (with nested selectors)
Example code:
const Example = styled('a')(({ theme }) => ({
color: theme.palette.primary[700],
'&::before': {
width: 2,
height: 2,
backgroundColor: theme.palette.mode === 'dark' ? theme.palette.primary[600] : theme.palette.background.paper,
},
'& > span': {
color theme.palette.mode === 'dark' ? theme.palette.primary[400] : theme.palette.primary[500],
},
}))
Migrated code: use array:
const Example = styled('a')(
({ theme }) => ([{
color: theme.palette.primary[700],
'&::before': {
width: 2,
height: 2,
backgroundColor: (theme.vars || theme).palette.background.paper,
},
'& > span': {
color: (theme.vars || theme).palette.primary[500],
},
},
theme => theme.applyDarkStyles({
'&::before': {
backgroundColor: (theme.vars || theme).palette.primary[600],
},
'& > span': {
color: (theme.vars || theme).palette.primary[400],
}
})]))
5. img switch between color modes
From StoreTemplatesBanner.tsx.
Example code:
const globalTheme = useTheme();
const mode = globalTheme.palette.mode;
return (
<Image
ref={ref}
src={`/static/branding/store-templates/template-${mode}${Object.keys(linkMapping).indexOf(brand) + 1}.jpeg`}
alt=""
{...props}
/>
);
Migrated code: use CSS content: url(...):
<Image
ref={ref}
src={`/static/branding/store-templates/template-light${Object.keys(linkMapping).indexOf(brand) + 1}.jpeg`}
alt=""
sx={(theme) =>
theme.applyDarkStyles({
content: `url(/static/branding/store-templates/template-dark${Object.keys(linkMapping).indexOf(brand) + 1}.jpeg)`,
})
}
{...props}
/>
6. Section wrapped with <ThemeProvider theme={darkTheme}>
Remove the ThemeProvider and add data-mui-color-scheme="dark" to the next div instead.
diff --git a/docs/pages/careers.tsx b/docs/pages/careers.tsx
index b06294da66..1ae0709c22 100644
--- a/docs/pages/careers.tsx
+++ b/docs/pages/careers.tsx
@@ -476,8 +476,7 @@ function CareersContent() {
</Container>
{/* Next roles */}
{nextRolesData.length > 0 ? (
- <ThemeProvider theme={brandingDarkTheme}>
- <Box sx={{ bgcolor: 'primaryDark.700' }}>
+ <Box data-mui-color-scheme="dark" sx={{ bgcolor: 'primaryDark.700' }}>
<Container sx={{ py: { xs: 4, md: 8 } }}>
<Box
sx={{
@@ -531,7 +530,6 @@ function CareersContent() {
</Stack>
</Container>
</Box>
- </ThemeProvider>
) : null}
{/* Frequently asked questions */}
<Container sx={{ py: { xs: 4, sm: 6, md: 8 } }}>
Implementation details
-
We want to migrate the website page by page, so we create a new provider
BrandingCssVarsProvider.tsxas a replacement for the existingBrandingProvider. It is built on top of the publicCssVarsProviderAPI specific for mui.com which contains custom theme tokens. Once a page is wrapped with the new provider, the components under it will start using CSS theme variables immediately which causes server-client inconsistency due to conditional expressions like thistheme.palette.mode === 'dark' ? theme.palette.grey[300] : theme.palette.grey[700] -
The
applyDarkStyles()util is added to the theme (this is specific to mui.com, not Material UI) to ease the migration because some components need to be backward compatible for some pages that haven’t been migrated. This util is straightforward as the name implies. It will decide the approach to use based on the theme, so you don’t have to know if the components are rendered in which provider. All you need to do is put the styles for dark mode to the util after the default styles. if the component is under the new BrandingCssVarsProvider:theme.applyDarkStyles({ color: (theme.vars || theme).palette.primary.main, }) // it returns :where([data-mui-color-scheme="dark"]) & { color: var(--muidocs-palette-primary-main); }if the component is under the old BrandingProvider:
theme.applyDarkStyles({ color: (theme.vars || theme).palette.primary.main, }) // it returns color: #ff0dc; -
We have added a workaround to make the
:where()selector works.
Issue Analytics
- State:
- Created a year ago
- Reactions:2
- Comments:16 (16 by maintainers)

Top Related StackOverflow Question
Thanks, everyone for the help!
@siriwatknp I would like to contribute too. Can you assign me the “About” page?