Usage
Learn the basics of working with MUI System and its utilities.
Why use MUI System?
MUI System's sx
prop lets you avoid writing unnecessary styled-component code, and instead define styles directly within the component itself.
This is especially useful for one-off components with custom designs.
The following code samples illustrate the difference between styled-components and sx
:
- Using the styled-components API:
const StatWrapper = styled('div')(
({ theme }) => `
background-color: ${theme.palette.background.paper};
box-shadow: ${theme.shadows[1]};
border-radius: ${theme.shape.borderRadius}px;
padding: ${theme.spacing(2)};
min-width: 300px;
`,
);
const StatHeader = styled('div')(
({ theme }) => `
color: ${theme.palette.text.secondary};
`,
);
const StyledTrend = styled(TrendingUpIcon)(
({ theme }) => `
color: ${theme.palette.success.dark};
font-size: 16px;
vertical-alignment: sub;
`,
);
const StatValue = styled('div')(
({ theme }) => `
color: ${theme.palette.text.primary};
font-size: 34px;
font-weight: ${theme.typography.fontWeightMedium};
`,
);
const StatDiff = styled('div')(
({ theme }) => `
color: ${theme.palette.success.dark};
display: inline;
font-weight: ${theme.typography.fontWeightMedium};
margin-left: ${theme.spacing(0.5)};
margin-right: ${theme.spacing(0.5)};
`,
);
const StatPrevious = styled('div')(
({ theme }) => `
color: ${theme.palette.text.secondary};
display: inline;
font-size: 12px;
`,
);
return (
<StatWrapper>
<StatHeader>Sessions</StatHeader>
<StatValue>98.3 K</StatValue>
<StyledTrend />
<StatDiff>18.77%</StatDiff>
<StatPrevious>vs last week</StatPrevious>
</StatWrapper>
);
- Using MUI System:
<Box
sx={{
bgcolor: 'background.paper',
boxShadow: 1,
borderRadius: 1,
p: 2,
minWidth: 300,
}}
>
<Box sx={{ color: 'text.secondary' }}>Sessions</Box>
<Box sx={{ color: 'text.primary', fontSize: 34, fontWeight: 'medium' }}>
98.3 K
</Box>
<Box
component={TrendingUpIcon}
sx={{ color: 'success.dark', fontSize: 16, verticalAlign: 'sub' }}
/>
<Box
sx={{
color: 'success.dark',
display: 'inline',
fontWeight: 'medium',
mx: 0.5,
}}
>
18.77%
</Box>
<Box sx={{ color: 'text.secondary', display: 'inline', fontSize: 12 }}>
vs. last week
</Box>
</Box>
The sx prop
MUI System's core utility is the sx
prop, which gives you a quick and efficient way to apply the correct design tokens directly to a React element.
This prop provides a superset of CSS (that is it contains all CSS properties and selectors in addition to custom ones) that maps values directly from the theme, depending on the CSS property used. It also simplifies the process of defining responsive values by referring to the breakpoints defined in the theme.
Visit the sx
prop page for complete details.
Responsive demo
The following demo shows how to use the sx
prop to apply custom styles and create a complex UI component using the Box
wrapper alone.
Resize the window to see the responsive breakpoints:
When to use MUI System
The sx
prop is best suited for applying one-off styles to custom components.
This is in contrast to the styled-components API, which is ideal for building components that need to support a wide variety of contexts. These components are used in many different parts of the application and support different combinations of props.
Performance tradeoffs
MUI System relies on CSS-in-JS. It works with both Emotion and styled-components.
Pros
- 📚 The
sx
prop uses a superset of CSS, so the syntax will be immediately familiar to you if you know CSS already. It also offers (optional) shorthand definitions that can save you time if you put in a little work to learn them upfront. These are documented in the Style utilities section of the primary navigation to the left. - 📦 The System auto-purges, so that only the CSS that's used on the page is sent to the client. The initial bundle size cost is fixed—it doesn't get any larger as you add more CSS properties. You pay the cost of @emotion/react and @mui/system. The total size is ~15 kB gzipped. But if you are already using an MUI Core component library like Material UI, then it comes with no extra overhead.
Cons
Runtime performance takes a hit.
Benchmark case | Code snippet | Time normalized |
---|---|---|
a. Render 1,000 primitives | <div className="…"> |
100ms |
b. Render 1,000 components | <Div> |
112ms |
c. Render 1,000 styled components | <StyledDiv> |
181ms |
d. Render 1,000 Box | <Box sx={…}> |
296ms |
Visit the benchmark folder for a reproduction of the metrics above.
We believe that for most use cases it's fast enough, but there are simple workarounds when performance becomes critical. For instance, when rendering a list with many items, you can use a CSS child selector to have a single "style injection" point (using d. for the wrapper and a. for each item).
API tradeoff
MUI System's unifying sx
prop helps to maintain the separation of concerns between CSS utilities and component business logic.
For instance, a color
prop on a button impacts multiple states (hover, focus, etc.), and is distinct from the CSS color
property.
Only the Box
, Stack
, Typography
, and Grid
components accept MUI System properties as props for this reason.
These components are designed to solve CSS problems—they are CSS component utilities.
Where to use MUI System
The sx
prop can be used in four different locations:
Core components
All Material UI and Joy UI components support the sx
prop.
Box
Box
is a lightweight component that gives access to the sx
prop, and can be used as a utility component, and as a wrapper for other components.
It renders a <div>
element by default.
Custom components
In addition to MUI System components, you can add the sx
prop to your custom components too, by using the styled
utility from @mui/material/styles
.
import { styled } from '@mui/material/styles';
const Div = styled('div')``;
Any element with the babel plugin
Visit the open GitHub issue regarding this topic to learn more.
How to use MUI System
Design tokens in the theme
Visit the System properties page to learn how the different CSS (and custom) properties are mapped to the theme keys.
Shorthands
There are many shorthands available for various CSS properties. These are documented on their respective Style utilities pages. Here is an example of a few:
<Box
sx={{
boxShadow: 1, // theme.shadows[1]
color: 'primary.main', // theme.palette.primary.main
m: 1, // margin: theme.spacing(1)
p: {
xs: 1, // [theme.breakpoints.up('xs')]: { padding: theme.spacing(1) }
},
zIndex: 'tooltip', // theme.zIndex.tooltip
}}
>
These shorthands are optional—they're great for saving time, but not necessary to use
Superset of CSS
The sx
prop supports CSS syntax including child and pseudo-selectors, media queries, raw CSS values, and more.
Here are a few examples of how you can implement these CSS features:
Using pseudo-selectors:
<Box sx={{ // some styles ":hover": { boxShadow: 6, }, }} >
Using media queries:
<Box sx={{ // some styles '@media print': { width: 300, }, }} >
Using nested selector:
<Box sx={{ // some styles '& .ChildSelector': { bgcolor: 'primary.main', }, }} >
Responsive values
The sx
prop simplifies the process of defining and implementing responsive breakpoints.
You can define a set of breakpoints in two different ways: as an object, or as an array.
Breakpoints as an object
The first option for breakpoints is to define them as an object, using the breakpoint values as keys.
Note that each property for a given breakpoint also applies to all larger breakpoints in the set.
For example, width: { lg: 100 }
is equivalent to theme.breakpoints.up('lg')
.
The following demo shows how to define a set of breakpoints using the object syntax:
The shorthand syntax is @{breakpoint}/{container}
:
- breakpoint: a number for
px
unit or a breakpoint key (e.g.sm
,md
,lg
,xl
for default breakpoints) or a valid CSS value (e.g.40em
). - container (optional): the name of the containment context.
Breakpoints as an array
The second option is to define your breakpoints as an array, from smallest to largest. Here's what that looks like:
You can skip breakpoints with the null
value:
<Box sx={{ width: [null, null, 300] }}>This box has a responsive width.</Box>
Custom breakpoints
You can also specify your own custom breakpoints, and use them as keys when defining the breakpoints object. Here is an example of how to do that:
import * as React from 'react';
import Box from '@mui/material/Box';
import { createTheme, ThemeProvider } from '@mui/material/styles';
const theme = createTheme({
breakpoints: {
values: {
mobile: 0,
tablet: 640,
laptop: 1024,
desktop: 1280,
},
},
});
export default function CustomBreakpoints() {
return (
<ThemeProvider theme={theme}>
<Box
sx={{
width: {
mobile: 100,
laptop: 300,
},
}}
>
This box has a responsive width
</Box>
</ThemeProvider>
);
}
If you are using TypeScript, you will also need to use module augmentation for the theme to accept the above values.
declare module '@mui/material/styles' {
interface BreakpointOverrides {
xs: false; // removes the `xs` breakpoint
sm: false;
md: false;
lg: false;
xl: false;
tablet: true; // adds the `tablet` breakpoint
laptop: true;
desktop: true;
}
}
Theme getter
If you wish to use the theme for a CSS property that is not supported natively by MUI System, then you can use a function as the value, in which you can access the theme object. The following demo shows how this works: