MUI Sandbox @ github
MUI 架構
Understanding MUI packages @ MUI v5
MUI Core
- Material UI(
@mui/material
):使用基於 Material Design 所設計出來的元件,同時包含「功能」和「樣式」。 - MUI Base(
@mui/base
):包含許多 Unstyled(headless)的 React UI 元件,只是用提供的「功能」,CSS 樣式的部分需要自己處理。 - MUI System(
@mui/system
):相對於只用「功能」的 MUI Base,MUI System 則是提供許多 CSS Utilities 可以使用,特別像是sx
,它需要搭配 MUI Base、MUI components 使用。
MUI System
MUI System @ MUI 5
sx
The sx prop @ MUI 5
MUI system 的 sx
特別適合用在一次性(one-ff)的元件。
一般使用
到 Properties 可以找到所有可以用的屬性名稱,以及可以直接使用到的 theme mapping,並且看 ${value}
的地方。
舉例來說:
- 如果寫
{ border: 3 }
,表示的即是border: 3px solid
- 如果寫
{ borderColor: 'success.dark' }
,對應的會是theme.palette.success.dark
的顏色 - 如果寫
{ gap: 3 }
,對應到的是theme.spacing(3)
- 如果寫
{ display: 'inline-block' }
,因為這裡沒有任何 mapping(none
),所以就是直接帶入該值 - 如果寫
{ fontFamily: 'fontFamily' }
,因為它的 mapping 是theme.typography[value]
,因此會套用theme.typography.fontFamily
,表示會套用預設的 font family。
一般來說,搭配 <Box />
使用 sx
是最簡單的方式:
<Box
sx={{
border: 1, // 1px solid
bgcolor: 'background.paper', // bgcolor 的 "c" 是小寫,theme.palette.background.paper
boxShadow: 1, // theme.shadows[1]
borderRadius: 2, // theme.shape.borderRadius * 2
p: 2, // theme.spacing(2)
minWidth: 300, // 300px
fontFamily: 'fontFamily', // theme.typography.fontFamily
}}
/>
除了可以把上述的 System keys 放在 sx
中使用外,也可以把它們當成 <Box />
的 props 帶入:
// 個人認為還是把 CSS 相關的屬性放在 `sx` 中集中管理比較好,和「功能」較相關的再用 props 傳下去。
<Box color="text.primary" fontSize={32} fontWeight="medium" fontFamily="fontFamily">
98.3 K
</Box>
個人認為還是把 CSS 相關的屬性放在 sx
中集中管理比較好,和「功能」較相關的再用 props 傳下去。
callback value:需要使用到 theme 時
需要的話,sx
的「值」或「屬性值」都可以帶 callback function,特別適合用在需要使用 theme
的時候:
// 屬性值使用 callback
<Box
sx={{
height: (theme) => theme.spacing(2),
}}
/>
// sx 的值使用 callback
<Box
sx={(theme) => ({
...theme.typography.body1,
color: theme.palette.primary.main
})}
/>
Array values:特定情況下才套用特定樣式
<Box
sx={[
{
'&:hover': {
bgcolor: 'info.main',
color: 'info.contrastText',
},
},
checked && {
'&:hover': {
bgcolor: 'success.main',
color: 'success.contrastText',
},
},
]}
>
Array Values
</Box>
把 sx 當成 props 傳遞
Passing the sx prop @ MUI 5
- 定義型別的時候使用
SxProps<Theme>
// credit: https://mui.com/system/getting-started/the-sx-prop/#passing-the-sx-prop
import { SxProps, Theme } from '@mui/material/styles';
interface ListHeaderProps {
children: React.ReactNode;
sx?: SxProps<Theme>;
}
function ListHeader({ sx = [], children }: ListHeaderProps) {
return (
<ListItem
sx={[
{
width: 'auto',
textDecoration: 'underline',
},
// You cannot spread `sx` directly because `SxProps` (typeof sx) can be an array.
...(Array.isArray(sx) ? sx : [sx]),
]}
>
<FormLabel sx={{ color: 'inherit' }}>{children}</FormLabel>
</ListItem>
);
}
搭配 TypeScript 使用
如果你想要把套用到 sx
的物件存成一個變數使用,你「可能」需要搭配 as const
:
const style = {
bgcolor: 'background.paper', // bgcolor 的 "c" 是小寫
boxShadow: 1,
borderRadius: 2, // theme.shape.borderRadius * 1
p: 2,
minWidth: 300,
flexDirection: 'column',
} as const;
<Box sx={style} />;
筆者實測沒有使用 as const
也沒有發生型別上的錯誤(2022.10.30)。
客製化(Customization)
MUI Playground @ code sandbox
Theme
createMuiTheme
是 material ui 4 的用法;createTheme
是 MUI 5 的用法。
查看 Default theme 可以知道所有可以覆蓋的預設樣式。
useTheme
在元件中,可以使用 useTheme
來取得 theme,或是用 theme 中提供的 utility,例如 theme.spacing()
。
修改預設主題樣式
Theming @ MUI > Customization
使用 createTheme()
可以添加或修改預設的樣式,它會回傳一個新的 theme
,接著只要把這個 theme
放到 <ThemeProvider>
中,即可套用新的主題樣式。
在 MUI 中,所有預設的樣式都列在 Default theme 中,可以找到欲改變的屬性並覆蓋即可。
舉例來說,如果想改變預設 primary
的樣式,在文件 Default theme 中可以看到它的屬性被放在 palette.primary
中:
接著使用 createTheme
將該屬性的預設值覆蓋掉,並帶入 <ThemeProvider>
即可覆蓋掉預設的樣式:
import { orange } from '@mui/material/colors';
import { createTheme } from '@mui/material/styles';
export const theme = createTheme({
// 修改預設的樣式
palette: {
primary: {
main: orange[300],
// light: MUI 會自動根據 main 來推算顏色
dark: orange[500],
// contrastText: MUI 會自動根據 main 來推算顏色
},
},
});
export default function CustomStyles() {
return (
<ThemeProvider theme={theme}>
<CustomCheckbox defaultChecked />
</ThemeProvider>
);