init project
Some checks failed
No response / noResponse (push) Has been cancelled
CI / Continuous releases (push) Has been cancelled
CI / test-dev (macos-latest) (push) Has been cancelled
CI / test-dev (ubuntu-latest) (push) Has been cancelled
CI / test-dev (windows-latest) (push) Has been cancelled
Maintenance / main (push) Has been cancelled
Scorecards supply-chain security / Scorecards analysis (push) Has been cancelled
CodeQL / Analyze (push) Has been cancelled

This commit is contained in:
how2ice
2025-12-12 14:26:25 +09:00
commit 005cf56baf
43188 changed files with 1079531 additions and 0 deletions

View File

@@ -0,0 +1,37 @@
import { ThemeProvider, createTheme } from '@mui/material/styles';
import GlobalStyles from '@mui/material/GlobalStyles';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
const theme = createTheme({
cssVariables: {
nativeColor: true,
cssVarPrefix: 'alias', // This is for the demo only, you don't need to set this to use the feature
},
palette: {
primary: {
main: 'var(--colors-brand-primary)',
},
},
});
export default function AliasColorVariables() {
return (
<div>
{/* This is just a demo to replicate the global CSS file */}
<GlobalStyles
styles={{
':root': {
'--colors-brand-primary': 'oklch(0.85 0.2 83.89)',
},
}}
/>
{/* Your App */}
<ThemeProvider theme={theme}>
<Box sx={{ p: 2 }}>
<Button variant="contained">Branded Button</Button>
</Box>
</ThemeProvider>
</div>
);
}

View File

@@ -0,0 +1,38 @@
import { ThemeProvider, createTheme } from '@mui/material/styles';
import GlobalStyles from '@mui/material/GlobalStyles';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
const theme = createTheme({
cssVariables: {
nativeColor: true,
cssVarPrefix: 'alias', // This is for the demo only, you don't need to set this to use the feature
},
palette: {
primary: {
main: 'var(--colors-brand-primary)',
},
},
});
export default function AliasColorVariables() {
return (
<div>
{/* This is just a demo to replicate the global CSS file */}
<GlobalStyles
styles={{
':root': {
'--colors-brand-primary': 'oklch(0.85 0.2 83.89)',
},
}}
/>
{/* Your App */}
<ThemeProvider theme={theme}>
<Box sx={{ p: 2 }}>
<Button variant="contained">Branded Button</Button>
</Box>
</ThemeProvider>
</div>
);
}

View File

@@ -0,0 +1,15 @@
{/* This is just a demo to replicate the global CSS file */}
<GlobalStyles
styles={{
':root': {
'--colors-brand-primary': 'oklch(0.85 0.2 83.89)',
},
}}
/>
{/* Your App */}
<ThemeProvider theme={theme}>
<Box sx={{ p: 2 }}>
<Button variant="contained">Branded Button</Button>
</Box>
</ThemeProvider>

View File

@@ -0,0 +1,122 @@
import * as React from 'react';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import Slider from '@mui/material/Slider';
const theme = createTheme({
cssVariables: {
nativeColor: true,
cssVarPrefix: 'contrast', // This is for the demo only, you don't need to set this to use the feature
},
});
export default function ContrastTextDemo() {
const [lightness, setLightness] = React.useState(0.65);
const [chroma, setChroma] = React.useState(0.3);
const [hue, setHue] = React.useState(29);
// Create OKLCH color from slider values
const backgroundColor = `oklch(${lightness} ${chroma} ${hue})`;
// Get contrast text using theme function
const contrastText = theme.palette.getContrastText(backgroundColor);
return (
<ThemeProvider theme={theme}>
<Box
sx={{
p: 2,
display: 'flex',
gap: 5,
alignItems: 'flex-start',
justifyContent: 'center',
width: '100%',
flexWrap: 'wrap',
}}
>
{/* Live Preview Square */}
<Box
sx={{
mt: 2,
width: 200,
height: 200,
bgcolor: backgroundColor,
color: contrastText,
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
textAlign: 'center',
borderRadius: 1,
border: '1px solid',
borderColor: 'divider',
flexShrink: 0,
}}
>
<Typography variant="body2" fontFamily="monospace">
{backgroundColor}
</Typography>
</Box>
{/* Sliders */}
<Box sx={{ flex: '1 1 300px', maxWidth: 400 }}>
<Typography variant="h6" gutterBottom>
OKLCH
</Typography>
<div>
<Typography variant="body2" gutterBottom>
Lightness: {lightness}
</Typography>
<Slider
value={lightness}
onChange={(_, value) => setLightness(value)}
min={0}
max={1}
step={0.01}
valueLabelDisplay="auto"
/>
</div>
<div>
<Typography variant="body2" gutterBottom>
Chroma: {chroma}
</Typography>
<Slider
value={chroma}
onChange={(_, value) => setChroma(value)}
min={0}
max={0.4}
step={0.01}
valueLabelDisplay="auto"
/>
</div>
<div>
<Typography variant="body2" gutterBottom>
Hue: {hue}°
</Typography>
<Slider
value={hue}
onChange={(_, value) => setHue(value)}
min={0}
max={360}
step={1}
valueLabelDisplay="auto"
/>
</div>
</Box>
<Box
sx={{
p: 2,
display: 'flex',
gap: 3,
}}
>
<Typography variant="body2" fontFamily="monospace">
<b>Text color:</b> {contrastText}
</Typography>
</Box>
</Box>
</ThemeProvider>
);
}

View File

@@ -0,0 +1,122 @@
import * as React from 'react';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import Slider from '@mui/material/Slider';
const theme = createTheme({
cssVariables: {
nativeColor: true,
cssVarPrefix: 'contrast', // This is for the demo only, you don't need to set this to use the feature
},
});
export default function ContrastTextDemo() {
const [lightness, setLightness] = React.useState(0.65);
const [chroma, setChroma] = React.useState(0.3);
const [hue, setHue] = React.useState(29);
// Create OKLCH color from slider values
const backgroundColor = `oklch(${lightness} ${chroma} ${hue})`;
// Get contrast text using theme function
const contrastText = theme.palette.getContrastText(backgroundColor);
return (
<ThemeProvider theme={theme}>
<Box
sx={{
p: 2,
display: 'flex',
gap: 5,
alignItems: 'flex-start',
justifyContent: 'center',
width: '100%',
flexWrap: 'wrap',
}}
>
{/* Live Preview Square */}
<Box
sx={{
mt: 2,
width: 200,
height: 200,
bgcolor: backgroundColor,
color: contrastText,
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
textAlign: 'center',
borderRadius: 1,
border: '1px solid',
borderColor: 'divider',
flexShrink: 0,
}}
>
<Typography variant="body2" fontFamily="monospace">
{backgroundColor}
</Typography>
</Box>
{/* Sliders */}
<Box sx={{ flex: '1 1 300px', maxWidth: 400 }}>
<Typography variant="h6" gutterBottom>
OKLCH
</Typography>
<div>
<Typography variant="body2" gutterBottom>
Lightness: {lightness}
</Typography>
<Slider
value={lightness}
onChange={(_, value) => setLightness(value)}
min={0}
max={1}
step={0.01}
valueLabelDisplay="auto"
/>
</div>
<div>
<Typography variant="body2" gutterBottom>
Chroma: {chroma}
</Typography>
<Slider
value={chroma}
onChange={(_, value) => setChroma(value)}
min={0}
max={0.4}
step={0.01}
valueLabelDisplay="auto"
/>
</div>
<div>
<Typography variant="body2" gutterBottom>
Hue: {hue}°
</Typography>
<Slider
value={hue}
onChange={(_, value) => setHue(value)}
min={0}
max={360}
step={1}
valueLabelDisplay="auto"
/>
</div>
</Box>
<Box
sx={{
p: 2,
display: 'flex',
gap: 3,
}}
>
<Typography variant="body2" fontFamily="monospace">
<b>Text color:</b> {contrastText}
</Typography>
</Box>
</Box>
</ThemeProvider>
);
}

View File

@@ -0,0 +1,43 @@
import { ThemeProvider, createTheme } from '@mui/material/styles';
import Card from '@mui/material/Card';
import CardContent from '@mui/material/CardContent';
import CardActions from '@mui/material/CardActions';
import Alert from '@mui/material/Alert';
import Button from '@mui/material/Button';
const theme = createTheme({
cssVariables: {
nativeColor: true,
cssVarPrefix: 'colorSpace', // This is for the demo only, you don't need to set this to use the feature
},
palette: {
primary: {
main: 'oklch(0.65 0.3 28.95)',
},
warning: {
main: 'oklch(0.72 0.24 44.32)',
},
},
});
export default function CustomColorSpace() {
return (
<ThemeProvider theme={theme}>
<Card>
<CardContent>
<Alert severity="info" color="warning">
This theme uses the <code>oklch</code> color space.
</Alert>
</CardContent>
<CardActions sx={{ justifyContent: 'flex-end' }}>
<Button variant="contained" color="primary">
Submit
</Button>
<Button variant="outlined" color="primary">
Cancel
</Button>
</CardActions>
</Card>
</ThemeProvider>
);
}

View File

@@ -0,0 +1,43 @@
import { ThemeProvider, createTheme } from '@mui/material/styles';
import Card from '@mui/material/Card';
import CardContent from '@mui/material/CardContent';
import CardActions from '@mui/material/CardActions';
import Alert from '@mui/material/Alert';
import Button from '@mui/material/Button';
const theme = createTheme({
cssVariables: {
nativeColor: true,
cssVarPrefix: 'colorSpace', // This is for the demo only, you don't need to set this to use the feature
},
palette: {
primary: {
main: 'oklch(0.65 0.3 28.95)',
},
warning: {
main: 'oklch(0.72 0.24 44.32)',
},
},
});
export default function CustomColorSpace() {
return (
<ThemeProvider theme={theme}>
<Card>
<CardContent>
<Alert severity="info" color="warning">
This theme uses the <code>oklch</code> color space.
</Alert>
</CardContent>
<CardActions sx={{ justifyContent: 'flex-end' }}>
<Button variant="contained" color="primary">
Submit
</Button>
<Button variant="outlined" color="primary">
Cancel
</Button>
</CardActions>
</Card>
</ThemeProvider>
);
}

View File

@@ -0,0 +1,69 @@
import * as React from 'react';
import { createTheme, ThemeProvider, useColorScheme } from '@mui/material/styles';
import Stack from '@mui/material/Stack';
import MenuItem from '@mui/material/MenuItem';
import Switch from '@mui/material/Switch';
import Select from '@mui/material/Select';
import FormControlLabel from '@mui/material/FormControlLabel';
const theme = createTheme({
cssVariables: {
colorSchemeSelector: '.demo-disable-transition-%s',
},
colorSchemes: { dark: true },
});
function ModeSwitcher() {
const { mode, setMode } = useColorScheme();
if (!mode) {
return null;
}
return (
<Select
value={mode}
onChange={(event) => setMode(event.target.value)}
sx={{ minWidth: 120 }}
>
<MenuItem value="system">System</MenuItem>
<MenuItem value="light">Light</MenuItem>
<MenuItem value="dark">Dark</MenuItem>
</Select>
);
}
export default function DisableTransitionOnChange() {
const [disableTransition, setDisableTransition] = React.useState(false);
return (
<ThemeProvider
theme={theme}
disableNestedContext
disableTransitionOnChange={disableTransition}
>
<Stack
sx={{
width: '100%',
borderRadius: '4px',
p: 2,
gap: 2,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
bgcolor: 'background.default',
color: 'text.primary',
transition: '1s',
}}
>
<ModeSwitcher />
<FormControlLabel
control={
<Switch
checked={disableTransition}
onChange={(event) => setDisableTransition(event.target.checked)}
/>
}
label="Disable transition"
/>
</Stack>
</ThemeProvider>
);
}

View File

@@ -0,0 +1,71 @@
import * as React from 'react';
import { createTheme, ThemeProvider, useColorScheme } from '@mui/material/styles';
import Stack from '@mui/material/Stack';
import MenuItem from '@mui/material/MenuItem';
import Switch from '@mui/material/Switch';
import Select from '@mui/material/Select';
import FormControlLabel from '@mui/material/FormControlLabel';
const theme = createTheme({
cssVariables: {
colorSchemeSelector: '.demo-disable-transition-%s',
},
colorSchemes: { dark: true },
});
function ModeSwitcher() {
const { mode, setMode } = useColorScheme();
if (!mode) {
return null;
}
return (
<Select
value={mode}
onChange={(event) =>
setMode(event.target.value as 'system' | 'light' | 'dark')
}
sx={{ minWidth: 120 }}
>
<MenuItem value="system">System</MenuItem>
<MenuItem value="light">Light</MenuItem>
<MenuItem value="dark">Dark</MenuItem>
</Select>
);
}
export default function DisableTransitionOnChange() {
const [disableTransition, setDisableTransition] = React.useState(false);
return (
<ThemeProvider
theme={theme}
disableNestedContext
disableTransitionOnChange={disableTransition}
>
<Stack
sx={{
width: '100%',
borderRadius: '4px',
p: 2,
gap: 2,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
bgcolor: 'background.default',
color: 'text.primary',
transition: '1s',
}}
>
<ModeSwitcher />
<FormControlLabel
control={
<Switch
checked={disableTransition}
onChange={(event) => setDisableTransition(event.target.checked)}
/>
}
label="Disable transition"
/>
</Stack>
</ThemeProvider>
);
}

View File

@@ -0,0 +1,64 @@
import * as React from 'react';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import Radio from '@mui/material/Radio';
import RadioGroup from '@mui/material/RadioGroup';
import FormLabel from '@mui/material/FormLabel';
import FormControlLabel from '@mui/material/FormControlLabel';
import FormControl from '@mui/material/FormControl';
export default function ModernColorSpaces() {
const colorSpaces = [
{ value: 'color(display-p3 0.7 0.5 0)', label: 'display-p3()' }, // Mud
{ value: 'oklch(0.62 0.25 29)', label: 'oklch()' }, // Orange
{ value: 'oklab(0.59 0.1 -0.14)', label: 'oklab()' }, // Purple
{ value: 'hsl(141, 70%, 48%)', label: 'hsl()' }, // Green
{ value: 'rgb(25, 118, 210)', label: 'rgb()' }, // Blue
];
const [selectedColor, setSelectedColor] = React.useState(colorSpaces[0].value);
const theme = React.useMemo(
() =>
createTheme({
cssVariables: {
nativeColor: true,
cssVarPrefix: 'modern-color-spaces',
},
palette: {
primary: {
main: selectedColor,
},
},
}),
[selectedColor],
);
return (
<Box sx={{ display: 'flex', gap: 3, alignItems: 'center', flexWrap: 'wrap' }}>
<FormControl>
<FormLabel>Main color</FormLabel>
<RadioGroup
value={selectedColor}
onChange={(event) => setSelectedColor(event.target.value)}
>
{colorSpaces.map((colorSpace) => (
<FormControlLabel
key={colorSpace.value}
value={colorSpace.value}
control={<Radio />}
label={colorSpace.value}
/>
))}
</RadioGroup>
</FormControl>
<ThemeProvider theme={theme}>
<Button variant="contained" size="large">
Button
</Button>
</ThemeProvider>
</Box>
);
}

View File

@@ -0,0 +1,64 @@
import * as React from 'react';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import Radio from '@mui/material/Radio';
import RadioGroup from '@mui/material/RadioGroup';
import FormLabel from '@mui/material/FormLabel';
import FormControlLabel from '@mui/material/FormControlLabel';
import FormControl from '@mui/material/FormControl';
export default function ModernColorSpaces() {
const colorSpaces = [
{ value: 'color(display-p3 0.7 0.5 0)', label: 'display-p3()' }, // Mud
{ value: 'oklch(0.62 0.25 29)', label: 'oklch()' }, // Orange
{ value: 'oklab(0.59 0.1 -0.14)', label: 'oklab()' }, // Purple
{ value: 'hsl(141, 70%, 48%)', label: 'hsl()' }, // Green
{ value: 'rgb(25, 118, 210)', label: 'rgb()' }, // Blue
];
const [selectedColor, setSelectedColor] = React.useState(colorSpaces[0].value);
const theme = React.useMemo(
() =>
createTheme({
cssVariables: {
nativeColor: true,
cssVarPrefix: 'modern-color-spaces',
},
palette: {
primary: {
main: selectedColor,
},
},
}),
[selectedColor],
);
return (
<Box sx={{ display: 'flex', gap: 3, alignItems: 'center', flexWrap: 'wrap' }}>
<FormControl>
<FormLabel>Main color</FormLabel>
<RadioGroup
value={selectedColor}
onChange={(event) => setSelectedColor(event.target.value)}
>
{colorSpaces.map((colorSpace) => (
<FormControlLabel
key={colorSpace.value}
value={colorSpace.value}
control={<Radio />}
label={colorSpace.value}
/>
))}
</RadioGroup>
</FormControl>
<ThemeProvider theme={theme}>
<Button variant="contained" size="large">
Button
</Button>
</ThemeProvider>
</Box>
);
}

View File

@@ -0,0 +1,40 @@
import { ThemeProvider, createTheme } from '@mui/material/styles';
import Card from '@mui/material/Card';
import CardContent from '@mui/material/CardContent';
import CardActions from '@mui/material/CardActions';
import Alert from '@mui/material/Alert';
import Button from '@mui/material/Button';
const theme = createTheme({
cssVariables: {
nativeColor: true,
cssVarPrefix: 'nativeColor', // This is for the demo only, you don't need to set this to use the feature
colorSchemeSelector: 'data-mui-color-scheme',
},
colorSchemes: {
light: true,
dark: true,
},
});
export default function NativeCssColors() {
return (
<ThemeProvider theme={theme}>
<Card>
<CardContent>
<Alert severity="info">
This theme uses the <code>oklch</code> color space.
</Alert>
</CardContent>
<CardActions sx={{ justifyContent: 'flex-end' }}>
<Button variant="contained" color="primary">
Submit
</Button>
<Button variant="outlined" color="primary">
Cancel
</Button>
</CardActions>
</Card>
</ThemeProvider>
);
}

View File

@@ -0,0 +1,40 @@
import { ThemeProvider, createTheme } from '@mui/material/styles';
import Card from '@mui/material/Card';
import CardContent from '@mui/material/CardContent';
import CardActions from '@mui/material/CardActions';
import Alert from '@mui/material/Alert';
import Button from '@mui/material/Button';
const theme = createTheme({
cssVariables: {
nativeColor: true,
cssVarPrefix: 'nativeColor', // This is for the demo only, you don't need to set this to use the feature
colorSchemeSelector: 'data-mui-color-scheme',
},
colorSchemes: {
light: true,
dark: true,
},
});
export default function NativeCssColors() {
return (
<ThemeProvider theme={theme}>
<Card>
<CardContent>
<Alert severity="info">
This theme uses the <code>oklch</code> color space.
</Alert>
</CardContent>
<CardActions sx={{ justifyContent: 'flex-end' }}>
<Button variant="contained" color="primary">
Submit
</Button>
<Button variant="outlined" color="primary">
Cancel
</Button>
</CardActions>
</Card>
</ThemeProvider>
);
}

View File

@@ -0,0 +1,128 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import { blue, purple, red, green, orange, brown } from '@mui/material/colors';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import Typography from '@mui/material/Typography';
const theme = createTheme({
cssVariables: {
nativeColor: true,
// This is for the demo only, you don't need to set this to use the feature
cssVarPrefix: 'demo',
colorSchemeSelector: 'data',
},
colorSchemes: {
light: true,
dark: true,
},
});
const colorSwatches = [
{ color: blue[500] },
{ color: purple[500] },
{ color: red[500] },
{ color: brown[600] },
{ color: green[600] },
{ color: orange[500] },
];
function ColorDisplay({ color }) {
return (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
<Box
sx={{
width: 48,
height: 48,
bgcolor: color,
borderRadius: 1,
border: '1px solid',
borderColor: 'divider',
}}
/>
<Typography
variant="caption"
fontFamily="monospace"
color="text.secondary"
sx={{ wordBreak: 'break-all' }}
>
{color}
</Typography>
</Box>
);
}
ColorDisplay.propTypes = {
color: PropTypes.string.isRequired,
};
export default function ThemeColorFunctions() {
const [selectedColor, setSelectedColor] = React.useState(colorSwatches[0]);
const colorValues = {
alpha: theme.alpha(selectedColor.color, 0.5),
lighten: theme.lighten(selectedColor.color, 0.5),
darken: theme.darken(selectedColor.color, 0.5),
};
return (
<ThemeProvider theme={theme}>
<Box sx={{ p: 2 }}>
<Box sx={{ display: 'flex', gap: 1, mb: 3, flexWrap: 'wrap' }}>
{colorSwatches.map((swatch) => {
const isSelected = selectedColor.color === swatch.color;
return (
<Button
key={swatch.color}
variant={isSelected ? 'contained' : 'outlined'}
onClick={() => setSelectedColor(swatch)}
sx={(t) => ({
width: 56,
height: 56,
minWidth: 56,
p: 0,
fontSize: '0.625rem',
fontFamily: 'monospace',
borderColor: isSelected ? 'transparent' : swatch.color,
bgcolor: isSelected ? swatch.color : 'transparent',
color: isSelected
? t.palette.getContrastText(swatch.color)
: swatch.color,
})}
>
{swatch.color}
</Button>
);
})}
</Box>
<Box
sx={{
display: 'grid',
gap: 2,
gridTemplateColumns: 'repeat(auto-fit, minmax(280px, 1fr))',
}}
>
<div>
<Typography variant="subtitle2" gutterBottom fontWeight="medium">
theme.alpha(color, 0.5)
</Typography>
<ColorDisplay color={colorValues.alpha} />
</div>
<div>
<Typography variant="subtitle2" gutterBottom fontWeight="medium">
theme.lighten(color, 0.5)
</Typography>
<ColorDisplay color={colorValues.lighten} />
</div>
<div>
<Typography variant="subtitle2" gutterBottom fontWeight="medium">
theme.darken(color, 0.5)
</Typography>
<ColorDisplay color={colorValues.darken} />
</div>
</Box>
</Box>
</ThemeProvider>
);
}

View File

@@ -0,0 +1,123 @@
import * as React from 'react';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import { blue, purple, red, green, orange, brown } from '@mui/material/colors';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import Typography from '@mui/material/Typography';
const theme = createTheme({
cssVariables: {
nativeColor: true,
// This is for the demo only, you don't need to set this to use the feature
cssVarPrefix: 'demo',
colorSchemeSelector: 'data',
},
colorSchemes: {
light: true,
dark: true,
},
});
const colorSwatches = [
{ color: blue[500] },
{ color: purple[500] },
{ color: red[500] },
{ color: brown[600] },
{ color: green[600] },
{ color: orange[500] },
];
function ColorDisplay({ color }: { color: string }) {
return (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
<Box
sx={{
width: 48,
height: 48,
bgcolor: color,
borderRadius: 1,
border: '1px solid',
borderColor: 'divider',
}}
/>
<Typography
variant="caption"
fontFamily="monospace"
color="text.secondary"
sx={{ wordBreak: 'break-all' }}
>
{color}
</Typography>
</Box>
);
}
export default function ThemeColorFunctions() {
const [selectedColor, setSelectedColor] = React.useState(colorSwatches[0]);
const colorValues = {
alpha: theme.alpha(selectedColor.color, 0.5),
lighten: theme.lighten(selectedColor.color, 0.5),
darken: theme.darken(selectedColor.color, 0.5),
};
return (
<ThemeProvider theme={theme}>
<Box sx={{ p: 2 }}>
<Box sx={{ display: 'flex', gap: 1, mb: 3, flexWrap: 'wrap' }}>
{colorSwatches.map((swatch) => {
const isSelected = selectedColor.color === swatch.color;
return (
<Button
key={swatch.color}
variant={isSelected ? 'contained' : 'outlined'}
onClick={() => setSelectedColor(swatch)}
sx={(t) => ({
width: 56,
height: 56,
minWidth: 56,
p: 0,
fontSize: '0.625rem',
fontFamily: 'monospace',
borderColor: isSelected ? 'transparent' : swatch.color,
bgcolor: isSelected ? swatch.color : 'transparent',
color: isSelected
? t.palette.getContrastText(swatch.color)
: swatch.color,
})}
>
{swatch.color}
</Button>
);
})}
</Box>
<Box
sx={{
display: 'grid',
gap: 2,
gridTemplateColumns: 'repeat(auto-fit, minmax(280px, 1fr))',
}}
>
<div>
<Typography variant="subtitle2" gutterBottom fontWeight="medium">
theme.alpha(color, 0.5)
</Typography>
<ColorDisplay color={colorValues.alpha} />
</div>
<div>
<Typography variant="subtitle2" gutterBottom fontWeight="medium">
theme.lighten(color, 0.5)
</Typography>
<ColorDisplay color={colorValues.lighten} />
</div>
<div>
<Typography variant="subtitle2" gutterBottom fontWeight="medium">
theme.darken(color, 0.5)
</Typography>
<ColorDisplay color={colorValues.darken} />
</div>
</Box>
</Box>
</ThemeProvider>
);
}

View File

@@ -0,0 +1,321 @@
# CSS theme variables - Configuration
<p class="description">A guide for configuring CSS theme variables in Material UI.</p>
## Customizing variable prefix
To change the default variable prefix (`--mui`), provide a string to `cssVarPrefix` property, as shown below:
```js
createTheme({ cssVariables: { cssVarPrefix: 'any' } });
// generated stylesheet:
// --any-palette-primary-main: ...;
```
To remove the prefix, use an empty string as a value:
```js
createTheme({ cssVariables: { cssVarPrefix: '' } });
// generated stylesheet:
// --palette-primary-main: ...;
```
## Toggling dark mode manually
To toggle between modes manually, set the `colorSchemeSelector` with one of the following selectors:
- `class`: adds a class to the `<html>` element.
```js class
createTheme({
colorSchemes: { light: true, dark: true },
cssVariables: {
colorSchemeSelector: 'class'
}
});
// CSS Result
.light { ... }
.dark { ... }
```
- `data`: adds a data attribute to the `<html>` element.
```js data
createTheme({
colorSchemes: { light: true, dark: true },
cssVariables: {
colorSchemeSelector: 'data'
}
});
// CSS Result
[data-light] { ... }
[data-dark] { ... }
```
- `string`: adds a custom selector to the `<html>` element.
```js string
// The value must start with dot (.) for class or square brackets ([]) for data
createTheme({
colorSchemes: { light: true, dark: true },
cssVariables: {
colorSchemeSelector: '.theme-%s'
}
});
// CSS Result
.theme-light { ... }
.theme-dark { ... }
```
Then, use `useColorScheme` hook to switch between modes:
```jsx
import { useColorScheme } from '@mui/material/styles';
function ModeSwitcher() {
const { mode, setMode } = useColorScheme();
if (!mode) {
return null;
}
return (
<select
value={mode}
onChange={(event) => {
setMode(event.target.value);
// For TypeScript, cast `event.target.value as 'light' | 'dark' | 'system'`:
}}
>
<option value="system">System</option>
<option value="light">Light</option>
<option value="dark">Dark</option>
</select>
);
}
```
:::success
After React hydrates the tree, the mode is set to `system` to follow the user's preference.
:::
### Determining the system mode
To determine if the system mode is `light` or `dark`, use the `systemMode` property:
```js
const { mode, systemMode } = useColorScheme();
console.log(mode); // 'system'
console.log(systemMode); // 'light' | 'dark'
```
However, if the mode is **not** `system`, the `systemMode` will be `undefined`.
```js
const { mode, systemMode } = useColorScheme();
console.log(mode); // 'light' | 'dark'
console.log(systemMode); // undefined
```
### Preventing SSR flickering
For SSR (server-side rendering) applications, Material UI can not detected user-selected mode on the server, causing the screen to flicker from light to dark during the hydration phase on the client.
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()` function](/material-ui/customization/dark-mode/#styling-in-dark-mode):
```diff
import Card from '@mui/material/Card';
function App() {
return (
<Card
- sx={(theme) => ({
- backgroundColor: theme.palette.mode === 'dark' ? '#000' : '#fff',
- '&:hover': {
- backgroundColor: theme.palette.mode === 'dark' ? '#333' : '#f5f5f5',
- },
- })}
+ sx={[
+ {
+ backgroundColor: '#fff',
+ '&:hover': {
+ backgroundColor: '#f5f5f5',
+ },
+ },
+ (theme) =>
+ theme.applyStyles('dark', {
+ backgroundColor: '#000',
+ '&:hover': {
+ backgroundColor: '#333',
+ },
+ }),
+ ]}
/>
);
}
```
Next, if you have a custom selector that is **not** `media`, add the [`InitColorSchemeScript`](/material-ui/react-init-color-scheme-script/) component based on the framework that you are using:
:::success
The `attribute` has to be the same as the one you set in the `colorSchemeSelector` property:
```js
createTheme({
cssVariables: {
colorSchemeSelector: 'class'
}
})
<InitColorSchemeScript attribute="class" />
```
:::
### Next.js App Router
Add the following code to the [root layout](https://nextjs.org/docs/app/api-reference/file-conventions/layout#root-layouts) file:
```jsx title="app/layout.js"
import InitColorSchemeScript from '@mui/material/InitColorSchemeScript';
export default function RootLayout(props) {
return (
<html lang="en" suppressHydrationWarning>
<body>
{/* must come before the <main> element */}
<InitColorSchemeScript attribute="class" />
<main>{children}</main>
</body>
</html>
);
}
```
:::warning
If you don't add `suppressHydrationWarning` to your `<html>` tag, you will see warnings about `"Extra attributes from the server"` because `InitColorSchemeScript` updates that element.
:::
### Next.js Pages Router
Add the following code to the custom [`pages/_document.js`](https://nextjs.org/docs/pages/building-your-application/routing/custom-document) file:
```jsx title="pages/_document.js"
import Document, { Html, Head, Main, NextScript } from 'next/document';
import InitColorSchemeScript from '@mui/material/InitColorSchemeScript';
export default class MyDocument extends Document {
render() {
return (
<Html>
<Head>...</Head>
<body>
{/* must come before the <Main> element */}
<InitColorSchemeScript attribute="class" />
<Main />
<NextScript />
</body>
</Html>
);
}
}
```
### Gatsby
Place the script in your [`gatsby-ssr.js`](https://www.gatsbyjs.com/docs/reference/config-files/gatsby-ssr/) file:
```jsx
import * as React from 'react';
import InitColorSchemeScript from '@mui/material/InitColorSchemeScript';
export function onRenderBody({ setPreBodyComponents }) {
setPreBodyComponents([<InitColorSchemeScript attribute="class" />]);
}
```
## Forcing a specific color scheme
To force a specific color scheme for some part of your application, set the selector to the component or HTML element directly.
In the example below, all the components inside the `div` will always be dark:
<codeblock>
```js class
// if the selector is '.mode-%s'
<div className=".mode-dark">
<Paper sx={{ p: 2 }}>
<TextField label="Email" type="email" margin="normal" />
<TextField label="Password" type="password" margin="normal" />
<Button>Sign in</Button>
</Paper>
{/* other components */}
</div>
```
```js data-attribute
// if the selector is '[data-mode-%s]'
<div data-mode-dark>
<Paper sx={{ p: 2 }}>
<TextField label="Email" type="email" margin="normal" />
<TextField label="Password" type="password" margin="normal" />
<Button>Sign in</Button>
</Paper>
{/* other components */}
</div>
```
</codeblock>
## Disabling CSS color scheme
By default, `createTheme()` attaches a [CSS `color-scheme` property](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/color-scheme) based on the palette mode.
You can disable this by setting `disableCssColorScheme` to `true`:
```js
createTheme({
cssVariables: { disableCssColorScheme: true },
});
```
The generated CSS will not include the `color-scheme` property:
```diff
@media (prefers-color-scheme: dark) {
:root {
- color-scheme: dark;
--mui-palette-primary-main: #90caf9;
...
}
}
```
## Instant transition between color schemes
To disable CSS transitions when switching between modes, apply the `disableTransitionOnChange` prop:
```js
<ThemeProvider disableTransitionOnChange />
```
{{"demo": "DisableTransitionOnChange.js"}}
## Force theme recalculation between modes
By default, the `ThemeProvider` does not re-render when switching between light and dark modes when `cssVariables: true` is set in the theme.
If you want to opt-out from this behavior, use the `forceThemeRerender` prop in the ThemeProvider:
```js
<ThemeProvider forceThemeRerender />
```

View File

@@ -0,0 +1,99 @@
# CSS theme variables - Native color
<p class="description">Learn how to use native color with CSS theme variables.</p>
:::warning
This feature only works in modern browsers. Please check the [browser support](https://caniuse.com/css-relative-colors) before using it.
:::
## Benefits
- No need to use JavaScript to manipulate colors.
- Supports modern color spaces such as `oklch`, `oklab`, and `display-p3`.
- Supports color aliases to external CSS variables.
- Automatically calculates contrast text from the main color.
## Usage
Set `cssVariables` with `nativeColor: true` in the theme options.
Material UI will start using CSS color-mix and relative color instead of the JavaScript color manipulation.
:::success
Try inspecting the demo below to see the calculated values of the color tokens.
:::
```js
const theme = createTheme({
cssVariables: {
nativeColor: true,
},
});
```
{{"demo": "NativeCssColors.js"}}
## Modern color spaces
The theme palette supports all modern color spaces, including `oklch`, `oklab`, and `display-p3`.
```js
const theme = createTheme({
cssVariables: { nativeColor: true },
palette: {
primary: {
main: 'color(display-p3 0.5 0.8 0.2)',
},
},
});
```
{{"demo": "ModernColorSpaces.js"}}
## Aliasing color variables
If you're using CSS variables to define colors, you can provide the values to the theme palette options.
```js
const theme = createTheme({
cssVariables: {
nativeColor: true,
},
palette: {
primary: {
main: 'var(--colors-brand-primary)',
},
},
});
```
{{"demo": "AliasColorVariables.js"}}
## Theme color functions
The theme object contains these color utilities: `alpha()`, `lighten()`, and `darken()`.
When native color is enabled, these functions use CSS `color-mix()` and relative color instead of the JavaScript color manipulation.
{{"demo": "ThemeColorFunctions.js"}}
:::info
The theme color functions are backward compatible.
If native color is not enabled, they will fall back to the JavaScript color manipulation.
:::
## Contrast color function
The `theme.palette.getContrastText()` function produces the contrast color.
The demo below shows the result of the `theme.palette.getContrastText()` function, which produces the text color based on the selected background.
:::info
The CSS variables `--__l` and `--__a` are internal variables set globally by Material UI.
To learn more about the formulas used, see [this article on color contrast from Lea Verou](https://lea.verou.me/blog/2024/contrast-color/).
:::
## Caveats
- Because of the differences in how contrast is calculated between CSS and JavaScript, the resulting CSS colors may not exactly match the corresponding JavaScript colors to be replaced.
- In the future, the relative color contrast will be replaced by the native [CSS `contrast-color()` function](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/contrast-color) when browser support is improved.
- For relative color contrast, the color space is automatically set to `oklch` internally. Currently it's not possible to change this, but please [open an issue](https://github.com/mui/material-ui/issues/new/) if you have a use case that calls for it.

View File

@@ -0,0 +1,44 @@
# CSS theme variables
<p class="description">An overview of adopting CSS theme variables in Material UI.</p>
[CSS variables](https://www.w3.org/TR/css-variables-1/) are a modern cross-browser feature that let you declare variables in CSS and reuse them in other properties.
You can implement them to improve Material UI's theming and customization experience.
:::info
If this is your first time encountering CSS variables, you should check out [the MDN Web Docs on CSS custom properties](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_cascading_variables/Using_CSS_custom_properties) before continuing here.
:::
## Introduction
CSS theme variables replace raw values in Material UI components for a better developer experience because, in the browser dev tool, you will see which theme token is used as a value.
In addition with these variables, you can inject a theme into your app's stylesheet _at build time_ to apply the user's selected settings before the whole app is rendered.
## Advantages
- It lets you prevent [dark-mode SSR flickering](https://github.com/mui/material-ui/issues/27651).
- You can create unlimited color schemes beyond `light` and `dark`.
- It offers a better debugging experience not only for developers but also designers on your team.
- The color scheme of your website is automatically synced between browser tabs.
- It simplifies integration with third-party tools because CSS theme variables are available globally.
- It reduces the need for a nested theme when you want to apply dark styles to a specific part of your application.
## Trade-offs
For server-side applications, there are some trade-offs to consider:
| | Compare to the default method | Reason |
| :----------------------------------------------------------- | :---------------------------- | :------------------------------------------------------------------------------------------------------------- |
| HTML size | Bigger | CSS variables are generated for both light and dark mode at build time. |
| [First Contentful Paint (FCP)](https://web.dev/articles/fcp) | Longer | Since the HTML size is bigger, the time to download the HTML before showing the content is a bit longer. |
| [Time to Interactive (TTI)](https://web.dev/articles/tti) | Shorter (for dark mode) | Stylesheets are not regenerated between light and dark mode, a lot less time is spent running JavaScript code. |
:::warning
The comparison described in the table above may not be applicable to large and complex applications since there are so many factors that can impact performance metrics.
:::
## What's next
- To start a new project with CSS theme variables, check out the [basic usage guide](/material-ui/customization/css-theme-variables/usage/).
- For theming and customization, check out the [how-to guide](/material-ui/customization/css-theme-variables/configuration/).

View File

@@ -0,0 +1,257 @@
# CSS theme variables - Usage
<p class="description">Learn how to adopt CSS theme variables.</p>
## Getting started
To use CSS theme variables, create a theme with `cssVariables: true` and wrap your app with `ThemeProvider`.
After rendering, you'll see CSS variables in the `:root` stylesheet of your HTML document.
By default, these variables are flattened and prefixed with `--mui`:
<codeblock>
```jsx JSX
import { ThemeProvider, createTheme } from '@mui/material/styles';
const theme = createTheme({ cssVariables: true });
function App() {
return <ThemeProvider theme={theme}>{/* ...your app */}</ThemeProvider>;
}
```
```css CSS
:root {
--mui-palette-primary-main: #1976d2;
--mui-palette-primary-light: #42a5f5;
--mui-palette-primary-dark: #1565c0;
--mui-palette-primary-contrastText: #fff;
/* ...other variables */
}
```
</codeblock>
:::info
If you're using the experimental `CssVarsProvider` API, replace it with `ThemeProvider`.
All features that were previously available to the `CssVarsProvider` are now available with the `ThemeProvider`.
:::
## Light and dark modes
When the [built-in dark color scheme](/material-ui/customization/dark-mode/#built-in-support) and `cssVariables` are enabled, both light and dark CSS variables are generated with the default CSS media `prefers-color-scheme` method.
This method works with server-side rendering without extra configuration. However, users won't be able to toggle between modes because the styles are based on the browser media.
If you want to be able to manually toggle modes, see the guide to [toggling dark mode manually](/material-ui/customization/css-theme-variables/configuration/#toggling-dark-mode-manually).
## Applying dark styles
To customize styles for dark mode, use the [`theme.applyStyles()` function](/material-ui/customization/dark-mode/#styling-in-dark-mode).
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) =>
theme.applyStyles('dark', {
backgroundColor: theme.vars.palette.grey[900],
}),
]}
/>;
```
:::warning
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
When the CSS variables feature is enabled, the `vars` node is added to the theme.
This `vars` object mirrors the structure of a serializable theme, with each value corresponding to a CSS variable.
- `theme.vars` (recommended): an object that refers to the CSS theme variables.
```js
const Button = styled('button')(({ theme }) => ({
backgroundColor: theme.vars.palette.primary.main, // var(--mui-palette-primary-main)
color: theme.vars.palette.primary.contrastText, // var(--mui-palette-primary-contrastText)
}));
```
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.
```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:
```css
/* external-scope.css */
.external-section {
background-color: var(--mui-palette-grey-50);
}
```
## Color channel tokens
Enabling `cssVariables` automatically generates channel tokens which are used to create translucent colors.
These tokens consist of color space channels without the alpha component, separated by spaces.
The colors are suffixed with `Channel`—for example:
```js
const theme = createTheme({ cssVariables: true });
console.log(theme.palette.primary.mainChannel); // '25 118 210'
// This token is generated from `theme.colorSchemes.light.palette.primary.main`.
```
You can use the channel tokens to create a translucent color like this:
```js
const theme = createTheme({
cssVariables: true,
components: {
MuiChip: {
styleOverrides: {
root: ({ theme }) => ({
variants: [
{
props: { variant: 'outlined', color: 'primary' },
style: {
backgroundColor: `rgba(${theme.vars.palette.primary.mainChannel} / 0.12)`,
},
},
],
}),
},
},
},
});
```
:::warning
Don't use a comma (`,`) as a separator because the channel colors use empty spaces to define [transparency](https://www.w3.org/TR/css-color-4/#transparency):
```js
`rgba(${theme.vars.palette.primary.mainChannel}, 0.12)`, // 🚫 this does not work
`rgba(${theme.vars.palette.primary.mainChannel} / 0.12)`, // ✅ always use `/`
```
:::
## Adding new theme tokens
You can add other key-value pairs to the theme input which will be generated as a part of the CSS theme variables:
```js
const theme = createTheme({
cssVariables: true,
colorSchemes: {
light: {
palette: {
// The best part is that you can refer to the variables wherever you like 🤩
gradient:
'linear-gradient(to left, var(--mui-palette-primary-main), var(--mui-palette-primary-dark))',
border: {
subtle: 'var(--mui-palette-neutral-200)',
},
},
},
dark: {
palette: {
gradient:
'linear-gradient(to left, var(--mui-palette-primary-light), var(--mui-palette-primary-main))',
border: {
subtle: 'var(--mui-palette-neutral-600)',
},
},
},
},
});
function App() {
return <ThemeProvider theme={theme}>...</ThemeProvider>;
}
```
Then, you can access those variables from the `theme.vars` object:
```js
const Divider = styled('hr')(({ theme }) => ({
height: 1,
border: '1px solid',
borderColor: theme.vars.palette.border.subtle,
backgroundColor: theme.vars.palette.gradient,
}));
```
Or use `var()` to refer to the CSS variable directly:
```css
/* global.css */
.external-section {
background-color: var(--mui-palette-gradient);
}
```
:::warning
If you're using a [custom prefix](/material-ui/customization/css-theme-variables/configuration/#customizing-variable-prefix), make sure to replace the default `--mui`.
:::
For **TypeScript**, you need to augment the [palette interfaces](#palette-interfaces).
## TypeScript
The theme variables type is not enabled by default. You need to import the module augmentation to enable the typings:
```ts
// The import can be in any file that is included in your `tsconfig.json`
import type {} from '@mui/material/themeCssVarsAugmentation';
import { styled } from '@mui/material/styles';
const StyledComponent = styled('button')(({ theme }) => ({
// ✅ typed-safe
color: theme.vars.palette.primary.main,
}));
```
### Palette interfaces
To add new tokens to the theme palette, you need to augment the `PaletteOptions` and `Palette` interfaces:
```ts
declare module '@mui/material/styles' {
interface PaletteOptions {
gradient: string;
border: {
subtle: string;
};
}
interface Palette {
gradient: string;
border: {
subtle: string;
};
}
}
```
## Next steps
If you need to support system preference and manual selection, check out the [advanced configuration](/material-ui/customization/css-theme-variables/configuration/)