React + TypeScript: MUIコンポーネントのスタイルをcreateTheme()のstyleOverridesキーでツリーごとに上書きする

[MUI](https://mui.com/)(本稿執筆時v5.4.1)のコンポーネントのスタイルは、ただCSSのクラスを割り当てるだけでは適用できないことが少なくありません。作法にしたがったカスタマイズが必要です。いくつかあるやり方の中から、「[Global style overrides](https://mui.com/customization/theme-components/#global-style-overrides)」で解説されている、コンポーネントツリーごとにスタイルを上書きする手順と注意についてご説明します。つぎのCodeSandboxのコードが`Button`と`Accordion`のスタイルをカスタマイズした作例です(2022/02/16に`TextField`を追加)。

#### React + TypeScript: Customizing style of MUI components
https://codesandbox.io/s/react-typescript-customizing-style-of-mui-components-hcrgu?file=/src/App.tsx


# `Button`のスタイルを替える
まずは、前出「Global style overrides」で紹介されている`Button`コンポーネントのコード例です。カスタマイズしたいコンポーネントツリーを[`ThemeProvider`](https://mui.com/styles/api/#themeprovider)で包みます(なお、「[Theme provider](https://mui.com/customization/theming/#theme-provider)」参照)。

その`theme`プロパティに定めるのが、[`createTheme()`](https://mui.com/customization/theming/#createtheme-options-args-theme)の戻り値です。引数のオプションオブジェクトには、カスタマイズするのがコンポーネントですので、[`components`](https://mui.com/customization/theme-components/)プロパティにコンポーネント名を与えてください。名前(`MuiButton`)は、APIリファレンスの「[Component name](https://mui.com/api/button/#component-name)」で調べます。スタイルを上書きするキーが[`styleOverrides`](https://mui.com/customization/theme-components/#global-style-overrides)です。CSSルールというのはどこに適用するかのキーワードで、やはりAPIリファレンスの「[CSS](https://mui.com/api/button/#css)」でお確かめください。CSSの定義の仕方は、基本的にReactのJSXに定める`style`と同じです。

つぎのコードで、`Button`コンポーネントのテキストカラーが黒、フォントは少し大きめの1remになりました。

```react:src/App.tsx
import { Button } from '@mui/material';
import { ThemeProvider, createTheme } from '@mui/material/styles';

const theme = createTheme({
	components: {
		// コンポーネント名
		MuiButton: {
			styleOverrides: {
				// CSSルール名
				root: {
					// CSS定義
					color: 'black',
					fontSize: '1rem',
				},
			},
		},
	},
});
function App() {
	return (
		<ThemeProvider theme={theme}>
			<Button>font-size: 1rem</Button>
		</ThemeProvider>
	);
}

export default App;
```


# `Accordion`のスタイルを替えるときは注意が必要
`Button`コンポーネントのカスタマイズは簡単にできました。厚切りジェイソンなら「OK！パターン見えてきたよ！」と叫ぶところです。ところが、`Accordion`で「Why MUI!!」という羽目に。

![pose_english_why_man.png](https://3.bp.blogspot.com/-crV1Malk_E0/Vq880bMqpGI/AAAAAAAA3fc/RdzWT01dDKU/s800/pose_english_why_man.png)

「Accordion」の「[Basic accordion](https://mui.com/components/accordion/#basic-accordion)」のコード例で試します。コンポーネント名は[`MuiAccordion`](https://mui.com/api/accordion/#component-name)です。つぎのコードは、追加・修正箇所のみ抜き出しました。たしかにこれで、`Accordion`コンポーネントのテキストカラーは青くなるのです。ところが、`fontSize: '2rem'`と加えても大きさが変わりません。フォントがらみの変更はきかないようです。

```react:src/App.tsx
import {
	Accordion,
	AccordionDetails,
	AccordionSummary,
	Typography
} from "@mui/material";
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';

const theme = createTheme({
	components: {
		MuiAccordion: {
			styleOverrides: {
				root: {
					color: 'blue',
				},
			},
		},
	},
});
function App() {
	return (
		<ThemeProvider theme={theme}>
			<Button>font-size: 1rem</Button>
			<div>
				<Accordion>
					<AccordionSummary
						expandIcon={<ExpandMoreIcon />}
						aria-controls="panel1a-content"
						id="panel1a-header"
					>
						<Typography>Accordion 1</Typography>
					</AccordionSummary>
					<AccordionDetails>
						<Typography>
							{/* ...[略]... */}
						</Typography>
					</AccordionDetails>
				</Accordion>
				{/* ...[略]... */}
			</div>
		</ThemeProvider>
	);
}
```

改めて確かめると、`Accordion`は複数のサブパーツから組み立てられています。そこで、カスタマイズの対象をそれらのコンポーネント名に差し替えてみたりもしました。それでも、フォントのスタイルは変わりません。落ち着いてコード例のJSXを見ると、テキストは[`Typography`](https://mui.com/components/typography/)コンポーネントに差し込まれています。コンポーネント名を[`MuiTypography`](https://mui.com/api/typography/#component-name)に書き替えたらビンゴでした(結果は、冒頭のCodeSandbox作例でお確かめください)。

```react:src/App.tsx
const theme = createTheme({
	components: {
		MuiTypography: {
			styleOverrides: {
				root: {
					color: 'blue',
					fontSize: '2rem',
				},
			},
		},
	},
});
```

MUIコンポーネントのスタイルには、親から子に受け継がれるものもあります。けれど、子コンポーネント独自に保持する場合もあるというのが教訓です。だからといって、JSXの子コンポーネントひとつずつに`style`プロパティを加えようとしたら、煩雑で管理しにくくなります。コンポーネントツリーを`ThemeProvider`で包み、`theme`で特定のコンポーネントを狙い撃ちして定めるのはスマートでしょう。ただ、仕組みや確かめるべきことの要領がつかめないと、とまどってしまいます。お気をつけください。


[2022/02/16以下追記]
# `TextField`上部に縮小表示される`label`のフォントサイズを大きくしたい
`TextField`コンポーネントに`label`プロパティを定めると、デフォルトではテキストがまずプレースホルダーのようにフィールド内に示され、フォーカスを入れると上部に縮小して表示されます。これがどうも小さく感じられてなりません。日本語は画数が多いからというのも理由です。「憂鬱な薔薇」などと与えた日には、とくに中高年にはつらいものがあるでしょう。

そこで、テキストフィード上部に縮小表示されたラベルのフォントサイズを大きくしたいというのがお題です。ラベルのコンポーネント名は[`MuiInputLabel`](https://mui.com/api/input-label/#component-name)だとわかりました。すると、前述のふたつのコンポーネントと同じく、`styleOverridesキ`ーで`theme`を上書きすればたしかにフォントサイズは大きくなります。けれど、それではプレースホルダーのテキストも変わってしまうのです。

縮小表示されたラベルだけスタイルを変えたいという場合には、[CSS](https://mui.com/api/input-label/#css)のルールから`shrink`を選んでください。

```react:src/App.tsx
const theme = createTheme({
	components: {
		MuiInputLabel: {
			styleOverrides: {
				shrink: {
					fontSize: '1.1rem'
				}
			}
		}
	}
});
```