Approaches
Learn which approach is recommended, depending on the situation, to customize Joy UI components.
- For customizing only a specific instance of a given component, use the
sx
prop. - To ensure every instance of a given component looks the same across you app, use theming.
- To create something that Joy UI doesn't support out of the box but still has design consistency, create a reusable component that uses Joy UI's theme design tokens.
sx
prop
The sx
prop provides a superset of CSS (contains all CSS properties/selectors, in addition to custom ones) that maps values directly from the theme, depending on the CSS property used.
Every Joy UI component supports it and it's a tool that allows you to quickly customize components on the spot.
Visit the sx
prop documentation to learn more about it.
Theming
The theme is an object where you define both your design language with foundational tokens such as color schemes, typography and spacing scales, and how each component, and their different variants and states, uses them.
Here are some examples that reproduce popular designs (only the light mode, though):
import { CssVarsProvider, extendTheme } from '@mui/joy/styles';
import Button from '@mui/joy/Button';
const githubTheme = extendTheme({
colorSchemes: {
light: {
palette: {
success: {
solidBg: '#2DA44E',
solidHoverBg: '#2C974B',
solidActiveBg: '#298E46',
},
neutral: {
outlinedBg: '#F6F8FA',
outlinedHoverBg: '#F3F4F6',
outlinedActiveBg: 'rgba(238, 239, 242, 1)',
outlinedBorder: 'rgba(27, 31, 36, 0.15)',
},
focusVisible: 'rgba(3, 102, 214, 0.3)',
},
},
},
focus: {
default: {
outlineWidth: '3px',
},
},
fontFamily: {
body: 'SF Pro Text, var(--gh-fontFamily-fallback)',
},
components: {
JoyButton: {
styleOverrides: {
root: ({ ownerState }) => ({
borderRadius: '6px',
boxShadow: '0 1px 0 0 rgba(27, 31, 35, 0.04)',
transition: '80ms cubic-bezier(0.33, 1, 0.68, 1)',
transitionProperty: 'color,background-color,box-shadow,border-color',
...(ownerState.size === 'md' && {
fontWeight: 600,
minHeight: '32px',
fontSize: '14px',
'--Button-paddingInline': '1rem',
}),
...(ownerState.color === 'success' &&
ownerState.variant === 'solid' && {
'--gh-palette-focusVisible': 'rgba(46, 164, 79, 0.4)',
border: '1px solid rgba(27, 31, 36, 0.15)',
'&:active': {
boxShadow: 'inset 0px 1px 0px rgba(20, 70, 32, 0.2)',
},
}),
...(ownerState.color === 'neutral' &&
ownerState.variant === 'outlined' && {
'&:active': {
boxShadow: 'none',
},
}),
}),
},
},
},
});
function App() {
return (
<CssVarsProvider theme={githubTheme}>
<Button>Solid</Button>
...other buttons
</CssVarsProvider>
);
};
Customizing theme tokens
Theme tokens refer to both low-level and global variant design tokens.
For example, instead of assigning the same hex code every time you want to change a given component's background color, you assign a theme token instead. If, at any point, you want to change that, you'd change in one place only, ensuring you consistency across all the components that use that theme token.
To print your own design language into Joy UI components, start by customizing these tokens first, as every component uses them.
To do that, always use the extendTheme
function as the customized tokens will be deeply merged into the default theme.
Under the hood, Joy UI will convert the tokens to CSS variables, enabling you to get them through theme.vars.*
, which is very convenient as you can use any styling solution to read those CSS vars.
import { CssVarsProvider, extendTheme } from '@mui/joy/styles';
const theme = extendTheme({
colorSchemes: {
light: {
palette: {
// affects all Joy components that has `color="primary"` prop.
primary: {
50: '#fffbeb',
100: '#fef3c7',
200: '#fde68a',
// 300, 400, ..., 800,
900: '#78350f',
},
},
},
},
fontFamily: {
display: 'Inter, var(--joy-fontFamily-fallback)',
body: 'Inter, var(--joy-fontFamily-fallback)',
},
});
function App() {
return <CssVarsProvider theme={theme}>...</CssVarsProvider>;
}
Customizing components
Each Joy UI component uses a pre-defined set of theme tokens.
For example, the default small Button
comes with fontSize: sm
by default.
To change that while ensuring that every instance of it has the same styles, do it targeting the component directly from the theme.
Here's a preview of how you'd change the button's font size to large:
import { CssVarsProvider, extendTheme } from '@mui/joy/styles';
import Button from '@mui/joy/Button';
const theme = extendTheme({
components: {
// The component identifier always start with `Joy${ComponentName}`.
JoyButton: {
styleOverrides: {
root: ({ theme }) => {
// theme.vars.* return the CSS variables.
fontSize: theme.vars.fontSize.lg, // 'var(--joy-fontSize-lg)'
},
},
},
},
});
function MyApp() {
return (
<CssVarsProvider theme={theme}>
<Button>Text</Button>
</CssVarsProvider>
);
}
Reusable component
Creating new and custom components is always an option when you don't find exactly what you're looking for.
You can, however, ensure design consistency with other Joy UI components by pulling styles from the theme through the styled
function.
You also gain the ability to use the sx
prop, which also accepts theme tokens, to customize this newly created component.