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