mui
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMUI 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
- removed from Modal - use
onBackdropClickinsteadonClose - All components now use standardized and
slotspatternslotProps - CSS layers support via config (works with Tailwind v4)
enableCssLayer
Material-UI v7(2025年3月发布)的组件使用、sx属性样式、主题集成和响应式设计模式。
注意:MUI v7相对v6的破坏性变更:
- 深度导入不再生效 - 请使用package exports字段
- Modal组件移除了- 改用
onBackdropClick替代onClose - 所有组件现在采用标准化的和
slots模式slotProps - 通过配置支持CSS层级(兼容Tailwind v4)
enableCssLayer
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 - 主题设置