mui

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

MUI v7 Patterns

MUI v7 组件模式

Purpose

用途

Material-UI v7 (released March 2025) patterns for component usage, styling with sx prop, theme integration, and responsive design.
Note: MUI v7 breaking changes from v6:
  • Deep imports no longer work - use package exports field
  • onBackdropClick
    removed from Modal - use
    onClose
    instead
  • All components now use standardized
    slots
    and
    slotProps
    pattern
  • CSS layers support via
    enableCssLayer
    config (works with Tailwind v4)
Material-UI v7(2025年3月发布)的组件使用、sx属性样式、主题集成和响应式设计模式。
注意:MUI v7相对v6的破坏性变更:
  • 深度导入不再生效 - 请使用package exports字段
  • Modal组件移除了
    onBackdropClick
    - 改用
    onClose
    替代
  • 所有组件现在采用标准化的
    slots
    slotProps
    模式
  • 通过
    enableCssLayer
    配置支持CSS层级(兼容Tailwind v4)

When to Use This Skill

适用场景

  • Styling components with MUI sx prop
  • Using MUI components (Box, Grid, Paper, Typography, etc.)
  • Theme customization and usage
  • Responsive design with MUI breakpoints
  • MUI-specific utilities and hooks

  • 使用MUI sx属性为组件设置样式
  • 使用MUI组件(Box、Grid、Paper、Typography等)
  • 主题定制与使用
  • 基于MUI断点的响应式设计
  • MUI专属工具与hooks

Quick Start

快速开始

Basic MUI Component

基础MUI组件

typescript
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>
  );
}

typescript
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>
  );
}

Styling Patterns

样式模式

Inline Styles (< 100 lines)

内联样式(少于100行)

For components with simple styling, define styles at the top:
typescript
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>
  );
}
对于样式简单的组件,在顶部定义样式:
typescript
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>
  );
}

Separate Styles File (>= 100 lines)

独立样式文件(不少于100行)

For complex components, create separate style file:
typescript
// 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>;
}

对于复杂组件,创建独立的样式文件:
typescript
// 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,
  },
  // ... 更多样式
};

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

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

Common Components

常用组件

Layout Components

布局组件

typescript
// 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>
typescript
// Box - 通用容器
<Box sx={{ p: 2, bgcolor: 'background.paper' }}>
  Content
</Box>

// Paper - 带阴影的容器
<Paper elevation={2} sx={{ p: 3 }}>
  Content
</Paper>

// Container - 居中且带最大宽度的容器
<Container maxWidth="lg">
  Content
</Container>

// Stack - 带间距的弹性容器
<Stack spacing={2} direction="row">
  <Item />
  <Item />
</Stack>

Grid System

网格系统

typescript
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>
typescript
import { Grid } from '@mui/material';

// 12列网格
<Grid container spacing={2}>
  <Grid item xs={12} md={6}>
    左半部分
  </Grid>
  <Grid item xs={12} md={6}>
    右半部分
  </Grid>
</Grid>

// 响应式网格
<Grid container spacing={3}>
  <Grid item xs={12} sm={6} md={4} lg={3}>
    卡片
  </Grid>
  {/* 重复添加更多卡片 */}
</Grid>

Typography

排版

typescript
<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>
typescript
<Typography variant="h1">标题1</Typography>
<Typography variant="h2">标题2</Typography>
<Typography variant="body1">正文文本</Typography>
<Typography variant="caption">小字文本</Typography>

// 自定义样式
<Typography
  variant="h4"
  sx={{
    color: 'primary.main',
    fontWeight: 600,
    mb: 2,
  }}
>
  自定义标题
</Typography>

Buttons

按钮

typescript
// 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>

typescript
// 样式变体
<Button variant="contained">填充按钮</Button>
<Button variant="outlined">轮廓按钮</Button>
<Button variant="text">文本按钮</Button>

// 颜色变体
<Button variant="contained" color="primary">主色</Button>
<Button variant="contained" color="secondary">次要色</Button>
<Button variant="contained" color="error">错误色</Button>

// 带图标按钮
import { Add as AddIcon } from '@mui/icons-material';

<Button startIcon={<AddIcon />}>添加项目</Button>

Theme Integration

主题集成

Using Theme Values

使用主题值

typescript
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>
  );
}
typescript
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,
      }}
    >
      主题化容器
    </Box>
  );
}

Theme in sx Prop

sx属性中使用主题

typescript
<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>

typescript
<Box
  sx={{
    // 在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
  }}
>
  内容
</Box>

// 高级用法:回调函数
<Box
  sx={(theme) => ({
    color: theme.palette.primary.main,
    '&:hover': {
      color: theme.palette.primary.dark,
    },
  })}
>
  悬停我
</Box>

Responsive Design

响应式设计

Breakpoints

断点

typescript
// 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>
typescript
// 移动端优先的响应式值
<Box
  sx={{
    width: {
      xs: '100%',    // 0-600px
      sm: '80%',     // 600-900px
      md: '60%',     // 900-1200px
      lg: '40%',     // 1200-1536px
      xl: '30%',     // 1536px以上
    },
  }}
>
  响应式宽度
</Box>

// 响应式显示
<Box
  sx={{
    display: {
      xs: 'none',    // 移动端隐藏
      md: 'block',   // 桌面端显示
    },
  }}
>
  仅桌面端可见
</Box>

Responsive Typography

响应式排版

typescript
<Typography
  sx={{
    fontSize: {
      xs: '1rem',
      md: '1.5rem',
      lg: '2rem',
    },
    lineHeight: {
      xs: 1.5,
      md: 1.75,
    },
  }}
>
  Responsive text
</Typography>

typescript
<Typography
  sx={{
    fontSize: {
      xs: '1rem',
      md: '1.5rem',
      lg: '2rem',
    },
    lineHeight: {
      xs: 1.5,
      md: 1.75,
    },
  }}
>
  响应式文本
</Typography>

Forms

表单

typescript
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>

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

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

Common Patterns

常见模式

Card Component

卡片组件

typescript
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>
typescript
import { Card, CardContent, CardActions, Typography, Button } from '@mui/material';

<Card>
  <CardContent>
    <Typography variant="h5" component="div">
      标题
    </Typography>
    <Typography variant="body2" color="text.secondary">
      描述
    </Typography>
  </CardContent>
  <CardActions>
    <Button size="small">了解更多</Button>
  </CardActions>
</Card>

Dialog/Modal

对话框/模态框

typescript
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>
typescript
import { Dialog, DialogTitle, DialogContent, DialogActions, Button } from '@mui/material';

<Dialog open={open} onClose={handleClose}>
  <DialogTitle>确认操作</DialogTitle>
  <DialogContent>
    确定要继续吗?
  </DialogContent>
  <DialogActions>
    <Button onClick={handleClose}>取消</Button>
    <Button onClick={handleConfirm} variant="contained">
      确认
    </Button>
  </DialogActions>
</Dialog>

Loading States

加载状态

typescript
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>

typescript
import { CircularProgress, Skeleton } from '@mui/material';

// 加载指示器
<Box sx={{ display: 'flex', justifyContent: 'center', p: 3 }}>
  <CircularProgress />
</Box>

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

MUI-Specific Hooks

MUI专属Hooks

useMuiSnackbar

useMuiSnackbar

typescript
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>;
}

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

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

  const handleSave = async () => {
    try {
      await saveData();
      showSuccess('保存成功');
    } catch (error) {
      showError('保存失败');
    }
  };

  return <Button onClick={handleSave}>保存</Button>;
}

Icons

图标

typescript
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>

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

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

Best Practices

最佳实践

1. Type Your sx Props

1. 为sx属性添加类型

typescript
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
};
typescript
import type { SxProps, Theme } from '@mui/material';

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

// ❌ 不推荐
const styles = {
  container: { p: 2 }, // 无类型安全
};

2. Use Theme Tokens

2. 使用主题令牌

typescript
// ✅ Good: Use theme tokens
<Box sx={{ color: 'primary.main', p: 2 }} />

// ❌ Avoid: Hardcoded values
<Box sx={{ color: '#1976d2', padding: '16px' }} />
typescript
// ✅ 推荐:使用主题令牌
<Box sx={{ color: 'primary.main', p: 2 }} />

// ❌ 不推荐:硬编码值
<Box sx={{ color: '#1976d2', padding: '16px' }} />

3. Consistent Spacing

3. 统一间距

typescript
// ✅ Good: Use spacing scale
<Box sx={{ p: 2, mb: 3, mt: 1 }} />

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

typescript
// ✅ 推荐:使用间距刻度
<Box sx={{ p: 2, mb: 3, mt: 1 }} />

// ❌ 不推荐:随机像素值
<Box sx={{ padding: '17px', marginBottom: '25px' }} />

Additional Resources

额外资源

For more detailed patterns, see:
  • styling-guide.md - Advanced styling patterns
  • component-library.md - Component examples
  • theme-customization.md - Theme setup
如需更详细的模式,请查看:
  • styling-guide.md - 高级样式模式
  • component-library.md - 组件示例
  • theme-customization.md - 主题设置