Reputation: 1537
I am having an issue trying to use MUI Styled () on bigger scale: can someone take a look at the code we used to use in prior versions and let me know how to replicate it in MUI V5.
Old way:
const useStyles = makeStyles((theme) => ({
root: {
backgroundColor: "#fdfdff",
},
pageHeader: {
padding: theme.spacing(4),
display: "flex",
marginBottom: theme.spacing,
},
pageIcon: {
display: "inline-block",
padding: theme.spacing(2),
color: "#3c44b1",
},
pageTitle: {
paddingLeft: theme.spacing(4),
"& .MuiTypography-subtitle2": {
opacity: "0.6",
},
},
}));
export default function PageHeader(props) {
const classes = useStyles();
const { title, subTitle, icon } = props;
return (
<Paper elevation={0} square className={classes.root}>
<div className={classes.pageHeader}>
<Card className={classes.pageIcon}>{icon}</Card>
<div className={classes.pageTitle}>
<Typography variant="h6" component="div">
{title}
</Typography>
<Typography variant="subtitle2" component="div">
{subTitle}
</Typography>
</div>
</div>
</Paper>
);
}
My attempt to accomplish the same in MUI V5 is not working properly. it renders but it doesn't look the same and it's all over the place.
const rootStyle = styled("div")({
backgroundColor: "#fdfdff",
});
const headerStyle = styled("div")(({ theme }) => ({
padding: theme.spacing(4),
display: "flex",
marginBottom: theme.spacing,
}));
const iconStyle = styled("div")(({ theme }) => ({
display: "inline-block",
padding: theme.spacing(2),
color: "#3c44b1",
}));
const titleStyle = styled("div")(({ theme }) => ({
paddingLeft: theme.spacing(4),
"& .MuiTypography-subtitle2": {
opacity: "0.6",
},
}));
export default function PageHeader(props) {
const { title, subTitle, icon } = props;
return (
<rootStyle>
<Paper elevation={0} square>
<headerStyle>
<iconStyle>
<Card>{icon}</Card>
</iconStyle>
<titleStyle>
<Typography variant="h6" component="div">
{title}
</Typography>
<Typography variant="subtitle2" component="div">
{subTitle}
</Typography>
</titleStyle>
</headerStyle>
</Paper>
</rootStyle>
);
}
I am new to MUI and there are not a lot of examples out there that cover this. I truly appreciate your help!
Upvotes: 8
Views: 11207
Reputation: 81156
Below is a v5 version of your code with the same look as the v4 version. I added default values for the props just for demonstration purposes.
You had two main issues:
You added additional div layers for the styling rather than styling the elements that originally received the styles (e.g. Paper
, Card
).
You assigned the styled
divs to variable names that start with a lowercase letter which caused them to be rendered as DOM tags rather than components (so the styling would have been completely ignored).
From https://reactjs.org/docs/components-and-props.html#rendering-a-component:
React treats components starting with lowercase letters as DOM tags.
import Paper from "@mui/material/Paper";
import Card from "@mui/material/Card";
import Typography from "@mui/material/Typography";
import { styled } from "@mui/material/styles";
import PersonIcon from "@mui/icons-material/Person";
const StyledPaper = styled(Paper)({
backgroundColor: "#fdfdff"
});
const HeaderDiv = styled("div")(({ theme }) => ({
padding: theme.spacing(4),
display: "flex",
marginBottom: theme.spacing
}));
const StyledCard = styled(Card)(({ theme }) => ({
display: "inline-block",
padding: theme.spacing(2),
color: "#3c44b1"
}));
const TitleDiv = styled("div")(({ theme }) => ({
paddingLeft: theme.spacing(4),
"& .MuiTypography-subtitle2": {
opacity: "0.6"
}
}));
export default function PageHeader(props) {
const {
title = "Title",
subTitle = "sub-title",
icon = <PersonIcon />
} = props;
return (
<StyledPaper elevation={0} square>
<HeaderDiv>
<StyledCard>{icon}</StyledCard>
<TitleDiv>
<Typography variant="h6" component="div">
{title}
</Typography>
<Typography variant="subtitle2" component="div">
{subTitle}
</Typography>
</TitleDiv>
</HeaderDiv>
</StyledPaper>
);
}
An alternative (and much more concise) way to convert the v4 code to v5 is to use the sx
prop:
import Paper from "@mui/material/Paper";
import Card from "@mui/material/Card";
import Typography from "@mui/material/Typography";
import PersonIcon from "@mui/icons-material/Person";
import Box from "@mui/material/Box";
export default function PageHeader(props) {
const {
title = "Title",
subTitle = "sub-title",
icon = <PersonIcon />
} = props;
return (
<Paper elevation={0} square sx={{ bgcolor: "#fdfdff" }}>
<Box sx={{ p: 4, display: "flex", mb: 1 }}>
<Card sx={{ display: "inline-block", p: 2, color: "#3c44b1" }}>
{icon}
</Card>
<Box sx={{ pl: 4, "& .MuiTypography-subtitle2": { opacity: 0.6 } }}>
<Typography variant="h6" component="div">
{title}
</Typography>
<Typography variant="subtitle2" component="div">
{subTitle}
</Typography>
</Box>
</Box>
</Paper>
);
}
Here is one more option using a single styled
call, though in my opinion this would be more brittle to maintain than the other options:
import Paper from "@mui/material/Paper";
import Card from "@mui/material/Card";
import Typography from "@mui/material/Typography";
import { styled } from "@mui/material/styles";
import PersonIcon from "@mui/icons-material/Person";
const StyledPaper = styled(Paper)(({ theme }) => ({
backgroundColor: "#fdfdff",
"& > div": {
padding: theme.spacing(4),
display: "flex",
marginBottom: theme.spacing(1),
"& .MuiCard-root": {
display: "inline-block",
padding: theme.spacing(2),
color: "#3c44b1"
},
"& > div": {
paddingLeft: theme.spacing(4),
"& .MuiTypography-subtitle2": {
opacity: "0.6"
}
}
}
}));
export default function PageHeader(props) {
const {
title = "Title",
subTitle = "sub-title",
icon = <PersonIcon />
} = props;
return (
<StyledPaper elevation={0} square>
<div>
<Card>{icon}</Card>
<div>
<Typography variant="h6" component="div">
{title}
</Typography>
<Typography variant="subtitle2" component="div">
{subTitle}
</Typography>
</div>
</div>
</StyledPaper>
);
}
Upvotes: 9