2021年9月16日に MUI (Material-UI) v5 が正式にリリースされました。Material-UI v4 のリリースが 2019年3月なので、約2年半ぶりのメジャーアップデートです。正式名称が Material-UI から MUI に変更になり、パッケージ名も @material-ui/*
から @mui/*
になりました。
MUI v5 ではコンポーネントのスタイリングの実装方法や記法が一新し、Material-UI v4 以前までの独特な記法から、Theme UI、chakra などで用いられている sx
Prop によるスタイリングになりました。
大幅な変更になるので、v4 からの移行コストは大きいですが、新たに MUI を学ぶ人には優しくなった印象です。
MUI v5 のスタイリング方法を v4 の記法と比較しながら紹介していきます。
yarn add @mui/material @emotion/react @emotion/styled
Introducing MUI Core v5.0
https://mui.com/blog/mui-core-v5/
スタイリングの実装方法
MUI v5 では、スタイリングのコアライブラリが JSS から emotion に変わりました。この記事では説明しないので、詳しく知りたい方は Introducing MUI Core v5.0 を参照してください。
さて、v4 では useStyles
という自作フックでコンポーネントのスタイリングをしていましたが、この変更によって v5 からはコンポーネントに sx
Prop で直接スタイルを書くことができます。
v4 と v5 の記法の違い
Material-UI v4 の記法
makeStyles
でスタイル用のフックを作成し、コンポーネント内で className を取得します。
import { makeStyles, createStyles } from '@material-ui/core/styles';
// フックを作成
const useStyles = makeStyles((theme) => createStyles({
root: {
color: theme.palette.primary.main,
padding: theme.spacing(2),
},
}));
function Hoge() {
// フックで className を取得
const classes = useStyles();
return (
<div className={classes.root}>
Hoge
</div>
);
}
MUI v5 の記法
sx
Prop にスタイルを直接記入します。
import Box from '@mui/material/Box';
function Hoge() {
return (
<Box sx={{ color: 'primary.main', p: 2 }}>
Hoge
</Box>
);
}
sx
Prop によって記述量がとても少なくなり、初心者にもわかりやすい記法になりました。
color に指定した primary.main
は、MUI テーマのパレットを利用する方法です。v5 で新たに導入されたこの記法では、theme
を引数に取る関数(後述)を指定しなくても MUI テーマのパレットを利用することができます。
MUI System
https://mui.com/system/basics/
Palette
https://mui.com/system/palette/
sx
Prop について
MUI v5 のすべてのコンポーネントは sx
Prop でスタイリング可能です。sx
Prop は従来の(React では非推奨ですが)style
Prop に似ていますが、MUI テーマに基づいたスタイリングや、レスポンシブで動的なスタイリングが容易という特徴があります。
<Box
sx={{
width: {
xs: 100, // theme.breakpoints.up('xs')
sm: 200, // theme.breakpoints.up('sm')
md: 300, // theme.breakpoints.up('md')
lg: 400, // theme.breakpoints.up('lg')
xl: 500, // theme.breakpoints.up('xl')
},
height: (theme) => theme.spacing(10) // => 80px (8px * 10)
}}
>
This box has a responsive width.
</Box>
sx
Prop では、v4 の makeStyle
によるスタイリングと同様に、値にtheme
を引数にとった関数を指定することができます。
The sx prop
https://mui.com/system/the-sx-prop/
<Box>
コンポーネントについて
<Box>
コンポーネントは、sx
Prop のプロパティを Prop として直接記述できる基礎的なコンポーネントです。実は v4 時代には既に導入されていましたが、パフォーマンスが低いという難点がありました。リリースノートによると、v5 では大幅にパフォーマンスが改善されたそうです。
import Box from '@mui/material/Box';
// padding: 16px (spacing(8px) * 2)
// background-color: theme.palette.primary.dark
<Box p={2} bgcolor="primary.dark" width={100} height={100}>
hoge
</Box>
<Box>
コンポーネントと <Typography>
コンポーネントではこの方法で、 sx
Prop を使わずにスタイルを設定することができます。
<Box>
Component
https://mui.com/components/box/
Properties
https://mui.com/system/properties/
一般の HTML 要素のスタイリング
<div>
や <span>
などの一般の HTML 要素は sx
Prop を持ちません。これらをスタイリングするには、<Box>
コンポーネント や <Typography>
コンポーネントを使い、component
Prop で HTML 要素を指定するといいでしょう。
import Box from '@mui/material/Box';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
interface ItemProps {
children: React.ReactNode;
}
function Item({ children }: ItemProps) {
return (
<Typography variant="body2" component="span" sx={{ backgroundColor: 'secondary.light', p: 1 }}>
{children}
</Typography>
);
}
function Hoge() {
return (
// py (padding-top, padding-bottom): { xs: 16px, sm: 8px }
<Box component="nav" sx={{ py: [2, 1] }}>
<Stack spacing={2} direction={{ xs: 'column', sm: 'row' }}>
<Item>Top</Item>
<Item>News</Item>
<Item>Site Map</Item>
</Stack>
</Box>
);
}
<Box>
Component
https://mui.com/components/box/
<Typography>
Component
https://mui.com/components/typography/
margin, padding と spacing
という単位
MUI にはスタイリングの統一感を出すために、padding や margin に指定するための spacing
という単位が存在します。spacing
は MUI テーマ で規定されていて、デフォルトでは 8px に設定されています。
sx
Prop や <Box>
コンポーネントで設定する padding や margin には、spacing
が単位として使われています。v4 では makeStyles
でフックを作る際に、theme.spacing
を使うことで spacing
の単位が明示的に使われていましたが、v5 になって spacing
という単位が暗黙的に使われるようになったので注意が必要です。
// margin-right: 8px (8px * 1)
<Typography component="span" sx={{ mr: 1 }}></Typography>
// padding-top, paading-bottom: 16px (8px * 2)
<Box py={2}></Box>
また、padding と margin だけは spacing
を単位に取りますが、その他のプロパティは基本的に px
を単位に取るので混同しないように注意が必要です。また、borderRadius
は独自の theme.shape.borderRadius
(デフォルトは spacing
の半分である 4px)という単位を取るので注意しましょう。
// 正円になる
<Box sx={{
display: 'flex',
width: 64, // => 64px
height: 64, // => 64px
borderRadius: 8, // => 32px (4px * 8)
}} />
<Box sx={{
display: 'flex',
width: (theme) => theme.spacing(8), // 64px
height: (theme) => theme.spacing(8), // 64px
borderRadius: 8, // 32px (4px * 8)
}}>
Spacing
https://mui.com/system/spacing/
感想
v3 以前の withStyles
、v4 の makeStyles
といった Material-UI 特有の記法は Material-UI 入門者にはやや難解な印象がありました。
v5 では sx
Prop で記述する形になったので、初心者にはわかりやすくなったものの、パレットカラーの記法や、padding, margin における spacing
の暗黙的な利用など、覚えなくてはいけない事柄は増えた印象です。とはいえ、この辺りはおそらく Theme UI や Tailwind CSS でも同じことでしょう。
MUI v5 のスタイリングの触りの部分だけをざっと説明しました。
この先は公式ドキュメント、特に MUI System の項を熟読することをお勧めします。
参考
- MUI
- Introducing MUI Core v5.0
- Migration from v4 to v5
- Material-UI v5を先取りする - Techtouch Developers Blog