If you are already familiar with styled components, you might want to use that along with the MUI. To use styled-component with MUI, there is styled()
utility. The official documentation of MUI doesn't have enough examples with the styled() utility. This article's purpose is to provide enough examples of styled() utility with both Javascript object syntax
& CSS like syntax
.
📑Table of Contents
- Basic
- MUI Theme in the styled() Utility
- Media Queries
- Child Component and Child Element
- Pseudo Classes
- Sibling Component
- Props
- sx Prop can be used as an Alternative to the styled Utility
Basic
Import
// You must import 'styled' utility form mui
import { styled } from '@mui/material/styles';
// Also, you must import the components which you are gonna use with the styled utility
import Box from '@mui/material/Box';
JavaScript Object Syntax
Let's create a component with styled()
utility by using JavaScript object syntax:
const Basic = styled(Box)({
backgroundColor: 'aliceblue',
color: 'darkslategray',
padding: '2rem',
textAlign:'center'
})
Note:
- Here, we are using the
Box
component but instead of theBox
component, we can use any other MUI component. We just need to import that component.- Instead of a component we can also use an HTML tag. To use HTML tag, we have to put the HTML tag inside quote,
styled('div')
.- Here, the variable name is
Basic
. Always make sure that the first letter of the variable is capital because it will work like a component and a component name has to start with a capital letter.
CSS Like Syntax
Instead of JavaScript object syntax, we can also have CSS-like syntax:
const Basic = styled(Box)`
background-color: aliceblue;
color: darkslategray;
padding: 2rem;
text-align: center;
`;
Note:
Don't forget the
backticks
Semicolon after ending backtick is optional.
MUI Theme in the styled() Utility
Take a look at the default theme of MUI.
JavaScript Object Syntax
const UsingTheme = styled(Box)(
({ theme }) => ({
backgroundColor: theme.palette.primary.light,
color: theme.palette.grey[900],
padding: theme.spacing(2),
textAlign: 'center',
...theme.typography.h6,
})
)
The following picture is showing the MUI default theme. In the picture, we can see that the h6
is an object. It has fontFamily
, fontWeight
, fontSize
, lineHeight
& letterSpacing
properties. We want all of them. So, we are destructuring it (...theme.typography.h6,
).
CSS Like Syntax
const UsingTheme = styled(Box)(
({ theme }) => `
background-color: ${theme.palette.primary.light};
color: ${theme.palette.grey[900]};
padding: ${theme.spacing(2)};
text-align: center;
${ /* here, we can't destructure like javascript object syntax. So, we need to manually access all the properties of 'h6' */'' }
font-size: ${theme.typography.h6.fontSize};
font-weight: ${theme.typography.h6.fontWeight};
font-family: ${theme.typography.h6.fontFamily};
line-height: ${theme.typography.h6.lineHeight};
letter-spacing: ${theme.typography.h6.letterSpacing};
`,
)
Media Queries
JavaScript Object Syntax
Let's see an example of using media queries with JavaScript Object Syntax:
const UsingMediaQuery = styled(Box)(
({ theme }) => ({
backgroundColor: theme.palette.primary.light,
color: theme.palette.grey[900],
"@media (min-width:640px)": {
backgroundColor: theme.palette.primary.dark,
color: theme.palette.grey[100],
},
/* here, we are accessing breakpoints' value from the theme */
[`@media screen and (min-width: ${theme.breakpoints.values.md}px)`]: {
backgroundColor: theme.palette.secondary.light,
color: theme.palette.grey[900],
},
})
)
CSS Like Syntax
const UsingMediaQuery = styled(Box)(
({ theme }) => `
background-color: ${theme.palette.primary.light};
color: ${theme.palette.grey[900]};
@media (min-width: 640px) {
background-color: ${theme.palette.primary.dark};
color: ${theme.palette.grey[100]};
}
${ /* here, we are accessing breakpoints' value from the theme */'' }
@media (min-width: ${theme.breakpoints.values.md}px) {
background-color: ${theme.palette.secondary.light};
color: ${theme.palette.grey[900]};
}
`,
)
We can't have same media query more than one time in JavaScript Object Syntax
Suppose, there is class a box-section
in the html and we are styling it by writing normal CSS:
@media (min-width: 640px) {
.box-section {
margin: 1rem;
}
}
@media (min-width: 640px) {
.box-section {
padding: 1rem;
}
}
In the above example, we can see that the both media query is actually same. So, it was enough to have one media query and all the properties inside it. But we have written the same media query twice. Writing same media query twice like the above example has no problem, the code will work perfectly.
But when we write the same media query multiple times while working with styled component's JavaScript Syntax, only the last media query's code will be executed:
const Box_Section = styled(Box)(
({ theme }) => ({
"@media (min-width:640px)": {
margin:'1rem'
},
"@media (min-width:640px)": {
padding:'1rem'
},
)}
)
In the above example, as the both media query is same, only the last media query's code will be executed. So, the Box_Section
component will only have padding
, not margin
.
Reason of this problem:
As we are working with JavaScript object here, we must have unique property name. But in the above example, we are having"@media (min-width:640px)"
property name twice. So, JavaScript is considering the last property name's value to be the updated version and only having that.
Note: This problem will not occur with
CSS Like Syntax
in styled components. We can have same media query more than one time just like normal CSS.
Child Component and Child Element
JSX
Suppose, we want the following JSX
:
<ParentComponent>
<div>Hi</div>
<Box className='childComponent'> Hello </Box>
</ParentComponent>
So, we need to create the ParentComponent
component and also need to style the child element div
and child component Box
.
JavaScript Object Syntax
const ParentComponent = styled(Box)(
({ theme }) => ({
backgroundColor: theme.palette.primary.light,
color: theme.palette.grey[900],
padding: theme.spacing(2),
textAlign: 'center',
// Child element
"> div": {
backgroundColor: theme.palette.error.dark,
color: theme.palette.grey[100]
},
// Child Component (We need to select the class or id which is used in the child component)
"> .childComponent": {
backgroundColor: theme.palette.success.dark,
color: theme.palette.grey[100]
},
})
)
Note:
- I haven't found a way to select an MUI component without the class or an id that is used in that child component. If you know any way other, please write it down in the comment section.
CSS Like Syntax
const ParentComponent = styled(Box)(
({ theme }) => `
background-color: ${theme.palette.primary.light};
color: ${theme.palette.grey[900]};
padding: ${theme.spacing(2)};
text-align: center;
${ /* Child element */'' }
> div {
background-color: ${theme.palette.error.dark};
color: ${theme.palette.grey[100]};
};
${ /* Child Component (We need to select the class or id which is used in the child component) */'' }
> .childComponent {
background-color: ${theme.palette.success.dark};
color: ${theme.palette.grey[100]};
};
`,
)
Pseudo Classes
JSX
Suppose, we want the following JSX
:
<PseudoClasses>
<div>Hi</div>
<Box className='childComponent'> Hello </Box>
</PseudoClasses>
So, we need to create the PseudoClasses
component and also need to style the child element div
and child component Box
with pseudo-classes.
JavaScript Object Syntax
const PseudoClasses = styled(Box)(
({ theme }) => ({
backgroundColor: theme.palette.primary.light,
color: theme.palette.grey[900],
padding: theme.spacing(2),
textAlign: 'center',
":hover": {
backgroundColor: theme.palette.primary.dark,
color: theme.palette.grey[100],
},
":active": {
backgroundColor: theme.palette.warning.dark,
color: theme.palette.grey[100],
},
// Pseudo select child element
":hover > div": {
backgroundColor: theme.palette.error.dark,
},
// Pseudo select child component (We need to select the class or id which is used in the child component)
":hover > .childComponent": {
backgroundColor: theme.palette.success.dark,
},
})
)
CSS Like Syntax
const PseudoClasses = styled(Box)(
({ theme }) => `
background-color: ${theme.palette.primary.light};
color: ${theme.palette.grey[900]};
padding: ${theme.spacing(2)};
text-align: center;
:hover {
background-color: ${theme.palette.primary.dark};
color: ${theme.palette.grey[100]};
};
:active {
background-color: ${theme.palette.warning.dark};
color: ${theme.palette.grey[100]};
};
${ /* Pseudo select child element */'' }
:hover > div {
background-color: ${theme.palette.error.dark};
};
${ /* Pseudo select child component (We need to select the class or id which is used in the child component) */'' }
:hover > .childComponent {
background-color: ${theme.palette.success.dark};
};
`,
)
Sibling Component
JSX
Suppose, we want the following JSX
:
<>
<MainComponent> Hello </MainComponent>
<Box className='siblingComponent'> Hi </Box>
</>
So, we need to create the MainComponent
and also need to style the sibling component Box
.
JavaScript Object Syntax
const MainComponent = styled(Box)(
({ theme }) => ({
backgroundColor: theme.palette.primary.light,
color: theme.palette.grey[900],
// Adjacent Sibling Component (We need to use class or id of the Sibling component)
"+ .siblingComponent": {
backgroundColor: theme.palette.success.dark,
color: theme.palette.grey[100]
},
})
)
Note:
Instead of a sibling component, if there was a sibling HTML tag, we could have a style that too (
"+ div"
).The adjacent sibling selector (
+
) is used to select an element that is directly after another specific element.
CSS Like Syntax
const MainComponent= styled(Box)(
({ theme }) => `
background-color: ${theme.palette.primary.light};
color: ${theme.palette.grey[900]};
${ /* Adjacent Sibling Component (We need to use class or id of the Sibling component) */'' }
+ .siblingComponent {
background-color: ${theme.palette.success.dark};
color: ${theme.palette.grey[100]};
};
`,
)
Props
JSX
Suppose, we want to have a component (TestingProp
) where we can pass two props: dark
& border
. The value of both props is boolean & the value will of these props controls the style of the component.
<>
<TestingProps border={true} dark={true}>Hello
</TestingProps>
</>
So, we need to create the TestingProps
component and also need work with the prop dark
& border
.
JavaScript Object Syntax (Without MUI Theme)
const TestingProps = styled(Box, {
// Configure which props should be forwarded on DOM
shouldForwardProp: (prop) => prop !== 'dark' && prop!== 'border'
})
(({ dark, border }) => ({
backgroundColor: dark? "black" : "white",
color: dark? "white" : "black",
border: border? "1rem solid pink" : 'none'
}));
What is this
shouldForwaredProp
?We may already know that MUI5 uses emotion as a default style engine. This
shouldForwardProp
is coming fromemotion
.shouldForwaredProp
is used to pass prop. In an example in the official documentation,shouldForwaredProp
is used, you can check the example if you want.
CSS Like Syntax (Without MUI Theme)
const TestingProps4 = styled(Box, {
// Configure which props should be forwarded on DOM
shouldForwardProp: (prop) => prop !== 'dark' && prop!== 'border'
})
(({ dark, border }) => `
background-color: ${dark? "black" : "white"};
color: ${dark? "white" : "black"};
border: ${border? "1rem solid pink" : 'none'}
`);
JavaScript Object Syntax (With MUI Theme)
const TestingProps = styled(Box, {
// Configure which props should be forwarded on DOM
shouldForwardProp: (prop) => prop !== 'dark' && prop!== 'border'
})
(({ dark, border, theme }) => ({
backgroundColor: dark? theme.palette.grey[900] : theme.palette.grey[100],
color: dark? theme.palette.grey[100] : theme.palette.grey[900],
border: border? `1rem solid ${theme.palette.primary.main}` : 'none'
}));
CSS Like Syntax (With MUI Theme)
const TestingProps = styled(Box, {
// Configure which props should be forwarded on DOM
shouldForwardProp: (prop) => prop !== 'dark' && prop!== 'border'
})
(({ dark, border, theme }) => `
background-color: ${dark? theme.palette.grey[900] : theme.palette.grey[100]};
color: ${dark? theme.palette.grey[100] : theme.palette.grey[900]};
border: ${border? `1rem solid ${theme.palette.primary.main}` : 'none'};
`);
Default Prop Value
We can also pass the default value for the props.
TestingProps.defaultProps = {
dark: false,
border: false
}
sx Prop can be used as an Alternative to the styled Utility
Setup
With the right setup, the sx
prop can replicate all functionalities provided by the Styled
utility:
const NewStyledComponent = (props) => {
const {sx, children, ...extra_props} = props;
return (
<Box
sx={{
backgroundColor: 'black',
...sx
}}
{...extra_props}
>
{children}
</Box>
);
}
How the Above Setup Ensures the Functionalities of the styled
Utility
The component accepts and renders
children
, allowing content to be placed inside, similar to a component created using the styled utility.Just as components created with the styled utility can accept the
sx
prop for additional styling, "NewStyledComponent" also accepts thesx
prop.The
...extra_props
in "NewStyledComponent" allows for the forwarding of any additional props to the Box component. For instance, props like "onSubmit" and "onClick" can be seamlessly passed and applied. This behavior aligns with components from the styled utility, which also accept a diverse range of props for various scenarios.
Additional Advantages of the sx
Prop Approach
- Conditional styling becomes more straightforward because we are essentially creating a standard React component. This allows us to accept and pass props as we typically would, without following the specific prop-accepting conventions of the styled utility.
- Working with media queries becomes more straightforward:
const NewStyledComponent = (props) => {
const {sx, children, ...extra_props} = props;
return (
<Box
sx={{
// media query
width: { xs: '15rem', sm: '12rem' },
...sx
}}
{...extra_props}
>
{children}
</Box>
);
}
- Accessing the theme does not pose much difficulty:
const NewStyledComponent = (props) => {
const {sx, children, ...extra_props} = props;
return (
<Box
sx={(theme) => ({
// accessing theme
backgroundColor: theme.palette.primary.main,
...sx
})}
{...extra_props}
>
{children}
</Box>
);
}
That's it. 😃 Thanks for reading. 🎉
Top comments (5)
To summarize
shouldForwardProp
:shouldForwardProp
is a function that can be used with MUI's styled function to control which props should be passed down to the underlying DOM element. By default, all props passed to a styled component will be forwarded to the underlying element.However, in some cases, you may want to exclude certain props from being passed down, such as custom props used only for styling. This is where
shouldForwardProp
comes in.shouldForwardProp
takes a prop name as a string and returns a boolean. If it returns true, the prop will be passed down to the underlying element. If it returns false, the prop will be excluded.Here's an example of using
shouldForwardProp
with MUI's styled function:In this example, the customProp prop will be excluded from being passed down to the underlying div element because the
shouldForwardProp
function returns false when the prop name is 'customProp'.What are benefits of using
styled
to creating a normal component?vs
If you configure your normal component a little bit more, you can achieve all the functionalities of the styled utility. Check out this section: sx Prop can be used as an Alternative to the styled Utility
Thanks a lot! I am new to MUI styled utility and this is much enlightening. 👌🏼
Thank you for your feedback. I am glad that you found the article enlightening. 😀