mcpField
M
mui

mui

github.com/softaworksデザイン・UI2.6k803 回インストール34 週間前に更新
リポジトリ

mui について

フロントエンドプロジェクトで MUI v7 を使うためのリファレンススキルです。コンポーネントのパターン、sx によるスタイリング、テーマ連携、レスポンシブ設計に加え、バージョン変更やスタイル構成も扱います。

主な機能

  1. 01MUI v7 のコンポーネントパターン
  2. 02sx プロパティによるスタイリング
  3. 03テーマ連携とデザイントークン
  4. 04レスポンシブブレークポイントの利用
  5. 05v7 の変更点と slots の指針

活用シーン

  1. 01MUI コンポーネントによるレイアウト構築
  2. 02テーマに沿った一貫性のあるスタイル適用
  3. 03ブレークポイントに応じたコンポーネント調整

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/softaworks/agent-toolkit --skill mui

インストール後、Claude Code で/muiを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

README.md
skill-rules-fragment.json
resources/
component-library.md
styling-guide.md
theme-customization.md

詳細

MUI v7 パターン

目的

Material-UI v7(2025年3月リリース)における、コンポーネントの使用法、sx プロップによるスタイリング、テーマ統合、レスポンシブデザインのパターンです。

注意: MUI v6 からの MUI v7 の破壊的変更:

  • ディープインポートは使用できなくなりました。パッケージの exports フィールドを使用してください
  • Modal から onBackdropClick が削除されました。代わりに onClose を使用してください
  • すべてのコンポーネントが標準化された slots と slotProps パターンを使用するようになりました
  • enableCssLayer 設定による CSS レイヤーのサポート(Tailwind v4 で動作します)

このスキルを使用するタイミング

  • MUI の sx プロップでコンポーネントをスタイリングするとき
  • MUI コンポーネント(Box、Grid、Paper、Typography など)を使用するとき
  • テーマのカスタマイズと使用を行うとき
  • MUI のブレークポイントによるレスポンシブデザインを行うとき
  • MUI 固有のユーティリティやフックを使用するとき

クイックスタート

基本的な MUI コンポーネント
import { Box, Typography, Button, Paper } from '@mui/material';
import type { SxProps, Theme } from '@mui/material';

const styles: Record<string, SxProps<Theme>> = {
  container: {
    p: 2,
    display: 'flex',
    flexDirection: 'column',
    gap: 2,
  },
  header: {
    mb: 3,
    fontSize: '1.5rem',
    fontWeight: 600,
  },
};

function MyComponent() {
  return (
    <Paper sx={styles.container}>
      <Typography sx={styles.header}>
        Title
      </Typography>
      <Button variant="contained">
        Action
      </Button>
    </Paper>
  );
}

スタイリングパターン

インラインスタイル(100行未満)

シンプルなスタイリングのコンポーネントでは、冒頭でスタイルを定義します:

import type { SxProps, Theme } from '@mui/material';

const componentStyles: Record<string, SxProps<Theme>> = {
  container: {
    p: 2,
    display: 'flex',
    flexDirection: 'column',
  },
  header: {
    mb: 2,
    color: 'primary.main',
  },
  button: {
    mt: 'auto',
    alignSelf: 'flex-end',
  },
};

function Component() {
  return (
    <Box sx={componentStyles.container}>
      <Typography sx={componentStyles.header}>Header</Typography>
      <Button sx={componentStyles.button}>Action</Button>
    </Box>
  );
}
別ファイルのスタイル(100行以上)

複雑なコンポーネントでは、スタイルを別ファイルに作成します:

// UserProfile.styles.ts
import type { SxProps, Theme } from '@mui/material';

export const userProfileStyles: Record<string, SxProps<Theme>> = {
  container: {
    p: 3,
    maxWidth: 800,
    mx: 'auto',
  },
  header: {
    display: 'flex',
    justifyContent: 'space-between',
    alignItems: 'center',
    mb: 3,
  },
  // ... many more styles
};

// UserProfile.tsx
import { userProfileStyles as styles } from './UserProfile.styles';

function UserProfile() {
  return <Box sx={styles.container}>...</Box>;
}

一般的なコンポーネント

レイアウトコンポーネント
// Box - Generic container
<Box sx={{ p: 2, bgcolor: 'background.paper' }}>
  Content
</Box>

// Paper - Elevated surface
<Paper elevation={2} sx={{ p: 3 }}>
  Content
</Paper>

// Container - Centered content with max-width
<Container maxWidth="lg">
  Content
</Container>

// Stack - Flex container with spacing
<Stack spacing={2} direction="row">
  <Item />
  <Item />
</Stack>
グリッドシステム
import { Grid } from '@mui/material';

// 12-column grid
<Grid container spacing={2}>
  <Grid item xs={12} md={6}>
    Left half
  </Grid>
  <Grid item xs={12} md={6}>
    Right half
  </Grid>
</Grid>

// Responsive grid
<Grid container spacing={3}>
  <Grid item xs={12} sm={6} md={4} lg={3}>
    Card
  </Grid>
  {/* Repeat for more cards */}
</Grid>
タイポグラフィ
<Typography variant="h1">Heading 1</Typography>
<Typography variant="h2">Heading 2</Typography>
<Typography variant="body1">Body text</Typography>
<Typography variant="caption">Small text</Typography>

// With custom styling
<Typography
  variant="h4"
  sx={{
    color: 'primary.main',
    fontWeight: 600,
    mb: 2,
  }}
>
  Custom Heading
</Typography>
ボタン
// Variants
<Button variant="contained">Contained</Button>
<Button variant="outlined">Outlined</Button>
<Button variant="text">Text</Button>

// Colors
<Button variant="contained" color="primary">Primary</Button>
<Button variant="contained" color="secondary">Secondary</Button>
<Button variant="contained" color="error">Error</Button>

// With icons
import { Add as AddIcon } from '@mui/icons-material';

<Button startIcon={<AddIcon />}>Add Item</Button>

テーマ統合

テーマ値の使用
import { useTheme } from '@mui/material';

function Component() {
  const theme = useTheme();

  return (
    <Box
      sx={{
        p: 2,
        bgcolor: theme.palette.primary.main,
        color: theme.palette.primary.contrastText,
        borderRadius: theme.shape.borderRadius,
      }}
    >
      Themed box
    </Box>
  );
}
sx プロップでのテーマ
<Box
  sx={{
    // Access theme in sx
    color: 'primary.main',          // theme.palette.primary.main
    bgcolor: 'background.paper',     // theme.palette.background.paper
    p: 2,                            // theme.spacing(2)
    borderRadius: 1,                 // theme.shape.borderRadius
  }}
>
  Content
</Box>

// Callback for advanced usage
<Box
  sx={(theme) => ({
    color: theme.palette.primary.main,
    '&:hover': {
      color: theme.palette.primary.dark,
    },
  })}
>
  Hover me
</Box>

レスポンシブデザイン

ブレークポイント
// Mobile-first responsive values
<Box
  sx={{
    width: {
      xs: '100%',    // 0-600px
      sm: '80%',     // 600-900px
      md: '60%',     // 900-1200px
      lg: '40%',     // 1200-1536px
      xl: '30%',     // 1536px+
    },
  }}
>
  Responsive width
</Box>

// Responsive display
<Box
  sx={{
    display: {
      xs: 'none',    // Hidden on mobile
      md: 'block',   // Visible on desktop
    },
  }}
>
  Desktop only
</Box>
レスポンシブなタイポグラフィ
<Typography
  sx={{
    fontSize: {
      xs: '1rem',
      md: '1.5rem',
      lg: '2rem',
    },
    lineHeight: {
      xs: 1.5,
      md: 1.75,
    },
  }}
>
  Responsive text
</Typography>

フォーム

import { TextField, Stack, Button } from '@mui/material';

<Box component="form" onSubmit={handleSubmit}>
  <Stack spacing={2}>
    <TextField
      label="Email"
      type="email"
      value={email}
      onChange={(e) => setEmail(e.target.value)}
      fullWidth
      required
      error={!!errors.email}
      helperText={errors.email}
    />
    <Button type="submit" variant="contained">Submit</Button>
  </Stack>
</Box>

一般的なパターン

カードコンポーネント
import { Card, CardContent, CardActions, Typography, Button } from '@mui/material';

<Card>
  <CardContent>
    <Typography variant="h5" component="div">
      Title
    </Typography>
    <Typography variant="body2" color="text.secondary">
      Description
    </Typography>
  </CardContent>
  <CardActions>
    <Button size="small">Learn More</Button>
  </CardActions>
</Card>
Dialog/Modal
import { Dialog, DialogTitle, DialogContent, DialogActions, Button } from '@mui/material';

<Dialog open={open} onClose={handleClose}>
  <DialogTitle>Confirm Action</DialogTitle>
  <DialogContent>
    Are you sure you want to proceed?
  </DialogContent>
  <DialogActions>
    <Button onClick={handleClose}>Cancel</Button>
    <Button onClick={handleConfirm} variant="contained">
      Confirm
    </Button>
  </DialogActions>
</Dialog>
ローディング状態
import { CircularProgress, Skeleton } from '@mui/material';

// Spinner
<Box sx={{ display: 'flex', justifyContent: 'center', p: 3 }}>
  <CircularProgress />
</Box>

// Skeleton
<Stack spacing={1}>
  <Skeleton variant="text" width="60%" />
  <Skeleton variant="rectangular" height={200} />
  <Skeleton variant="text" width="40%" />
</Stack>

MUI 固有のフック

useMuiSnackbar
import { useMuiSnackbar } from '@/hooks/useMuiSnackbar';

function Component() {
  const { showSuccess, showError, showInfo } = useMuiSnackbar();

  const handleSave = async () => {
    try {
      await saveData();
      showSuccess('Saved successfully');
    } catch (error) {
      showError('Failed to save');
    }
  };

  return <Button onClick={handleSave}>Save</Button>;
}

アイコン

import { Add as AddIcon, Delete as DeleteIcon } from '@mui/icons-material';
import { Button, IconButton } from '@mui/material';

<Button startIcon={<AddIcon />}>Add</Button>
<IconButton onClick={handleDelete}><DeleteIcon /></IconButton>

ベストプラクティス

1. sx プロップに型を付ける
import type { SxProps, Theme } from '@mui/material';

// ✅ Good
const styles: Record<string, SxProps<Theme>> = {
  container: { p: 2 },
};

// ❌ Avoid
const styles = {
  container: { p: 2 }, // No type safety
};
2. テーマトークンを使用する
// ✅ Good: Use theme tokens
<Box sx={{ color: 'primary.main', p: 2 }} />

// ❌ Avoid: Hardcoded values
<Box sx={{ color: '#1976d2', padding: '16px' }} />
3. 一貫したスペーシング
// ✅ Good: Use spacing scale
<Box sx={{ p: 2, mb: 3, mt: 1 }} />

// ❌ Avoid: Random pixel values
<Box sx={{ padding: '17px', marginBottom: '25px' }} />

追加リソース

より詳細なパターンについては、以下を参照してください:

コメント