MUIを使ってライトモードとダークモードを切り替える方法の備忘録。
追記
普通にこれで良かった
App.tsx
import Card from '@mui/material/Card'; // なぜかBoxだけサポートされていない
import { ThemeProvider, createTheme } from '@mui/material/styles';
const theme = createTheme({
// いい感じの色を生成してくれるっぽい
colorScheme: {
light: true,
dark: true,
},
// デフォルトのスタイルをオーバーライド
components: {
MuiCard: {
defaultProps: {
sx: {
bgcolor: 'white', // 'red'とかだと流石に無理
},
},
},
},
});
export function App() {
return (
<ThemeProvider theme={theme}>
<Card>
Hello, World!
</Card>
</ThemeProvider>
);
}
コード
App.tsx
import Box from '@mui/material/Box';
import { ThemeProvider, createTheme } from '@mui/material/styles';
/* Paletteの型宣言ににカスタムの色を追加 */
declare module '@mui/material/styles' {
interface Palette {
myBlack: string,
myGray: string,
}
interface PaletteOptions {
myBlack?: string,
myGray?: string,
}
}
const theme = createTheme({
/* 自動で色を切り替えてくれる */
colorSchemes: {
light: {
palette: {
/* ライトモードの時のみ採用 */
myBlack: 'white',
myGray: '#888888',
},
},
dark: {
palette: {
myBlack: 'black',
myGray: '#DDDDDD',
},
},
},
});
function Content() {
return (
<Box
sx={
theme => ({
/* Themeオブジェクトを使って色を指定する */
color: theme.palette.myBlack,
bgcolor: theme.palette.myGray,
})
}
>
<p>Hello, World!</p>
</Box>
);
}
export default function App() {
return (
<ThemeProvider theme={theme}>
<Content />
</ThemeProvider>
);
}
ポイント
-
colorSchemes
を使ってモードに応じた色を自動指定する - Themeオブジェクトから色を拾う
課題
-
palette
が簡単に肥大化する(一度しか使わない色でも指定が必要) -
palette
で色を指定し忘れるとスタイルが消える -
declare module
が面倒
余談:Next.js対応
Next.jsで上記のアプローチを取ろうとする際、createTheme()
を使ったコンポーネントをlayout.tsx
に含めるとエラーが発生する。コンポーネントをapp.tsx
のApp()
で使うようにすると解決する。