Clase 34 - Material UI
Material UI (MUI)
🤔 - ¿Qué es Material UI?
Material UI es una biblioteca de componentes React que implementa el sistema de diseño Material Design de Google. Proporciona componentes pre-construidos, personalizables y accesibles que siguen las mejores prácticas de diseño y usabilidad.
A diferencia de frameworks utility-first como TailwindCSS, Material UI adopta un enfoque “component-first”, ofreciendo componentes completos listos para usar con estilos y funcionalidades integradas.
💫 - Ventajas Principales
- Desarrollo Rápido: Componentes completos y funcionales desde el primer momento.
- Consistencia: Diseño cohesivo basado en Material Design con principios establecidos.
- Accesibilidad: Componentes construidos siguiendo estándares WAI-ARIA.
- Theming: Sistema robusto de temas para personalización global.
- TypeScript: Soporte completo y tipado fuerte out-of-the-box.
- Ecosistema: Amplia documentación, ejemplos y comunidad activa.
🧱 - Conceptos Básicos de Uso
🌱 - Componentes Core
Material UI funciona con componentes React importables que encapsulan estilos y lógica:
import { Button, Typography, Card, CardContent } from '@mui/material';
function MyComponent() { return ( <Card> <CardContent> <Typography variant="h4" component="h1" gutterBottom> Título Principal </Typography> <Typography variant="body1" color="text.secondary"> Contenido del componente con estilos automáticos </Typography> <Button variant="contained" color="primary"> Acción Principal </Button> </CardContent> </Card> );}🎭 - Sistema de Theming
MUI utiliza un sistema de temas centralizado basado en ThemeProvider:
import { createTheme, ThemeProvider } from '@mui/material/styles';
const theme = createTheme({ palette: { primary: { main: '#1976d2', }, secondary: { main: '#dc004e', }, }, typography: { h4: { fontWeight: 600, }, },});
function App() { return ( <ThemeProvider theme={theme}> {/* Todos los componentes heredan el tema */} <MyComponent /> </ThemeProvider> );}📏 - Sistema de Espaciado
MUI usa un sistema de espaciado basado en una función de spacing (por defecto 8px):
sx={{ p: 2 }}=padding: 16pxsx={{ m: 1 }}=margin: 8pxsx={{ mt: 3, mb: 2 }}=margin-top: 24px, margin-bottom: 16px
📱 - Responsive Design
El sistema responsive se maneja a través de breakpoints en el tema:
import { useTheme, useMediaQuery } from '@mui/material';
function ResponsiveComponent() { const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down('md'));
return ( <Box sx={{ display: 'flex', flexDirection: { xs: 'column', md: 'row' }, gap: { xs: 1, md: 2 }, p: { xs: 2, md: 4 } }}> {/* Contenido responsive */} </Box> );}Breakpoints predefinidos:
xs:- 0px y superiorsm:- 600px y superiormd:- 900px y superiorlg:- 1200px y superiorxl:- 1536px y superior
⚙️ - Sistema sx
La prop sx permite escribir estilos CSS-in-JS de manera eficiente:
<Box sx={{ backgroundColor: 'primary.main', color: 'primary.contrastText', p: 2, borderRadius: 2, boxShadow: 3, '&:hover': { backgroundColor: 'primary.dark', }, }}> Elemento con estilos personalizados</Box>🌙 - Dark Mode
MUI incluye soporte nativo para modo oscuro:
import { createTheme, ThemeProvider, CssBaseline } from '@mui/material/styles';
const theme = createTheme({ palette: { mode: 'dark', // 'light' o 'dark' },});
function App() { return ( <ThemeProvider theme={theme}> <CssBaseline /> {/* Resetea estilos base */} <MyComponent /> </ThemeProvider> );}⭐ - Ejemplos Prácticos
🎴 - Card Component Completo
import { Card, CardContent, CardMedia, CardActions, Typography, Button, Chip, Box} from '@mui/material';
function ProductCard({ product }) { return ( <Card sx={{ maxWidth: 345, boxShadow: 3, '&:hover': { boxShadow: 6 } }} > <CardMedia component="img" height="200" image={product.image} alt={product.title} /> <CardContent> <Box sx={{ display: 'flex', alignItems: 'center', mb: 1 }}> <Chip label={product.category} color="primary" size="small" /> </Box> <Typography variant="h6" component="h2" gutterBottom> {product.title} </Typography> <Typography variant="body2" color="text.secondary"> {product.description} </Typography> <Typography variant="h6" color="primary" sx={{ mt: 2 }}> ${product.price} </Typography> </CardContent> <CardActions> <Button size="small" variant="contained"> Comprar </Button> <Button size="small" variant="outlined"> Ver detalles </Button> </CardActions> </Card> );}📝 - Formulario con Validación
import { Box, TextField, Button, Typography, Paper, Alert} from '@mui/material';import { useState } from 'react';
function ContactForm() { const [formData, setFormData] = useState({ name: '', email: '', message: '' }); const [errors, setErrors] = useState({});
const handleSubmit = (e) => { e.preventDefault(); // Lógica de validación y envío };
return ( <Paper elevation={3} sx={{ p: 4, maxWidth: 500, mx: 'auto' }}> <Typography variant="h4" component="h1" gutterBottom> Contáctanos </Typography>
<Box component="form" onSubmit={handleSubmit} sx={{ mt: 2 }}> <TextField fullWidth label="Nombre" name="name" value={formData.name} onChange={(e) => setFormData({...formData, name: e.target.value})} error={!!errors.name} helperText={errors.name} margin="normal" required />
<TextField fullWidth label="Email" name="email" type="email" value={formData.email} onChange={(e) => setFormData({...formData, email: e.target.value})} error={!!errors.email} helperText={errors.email} margin="normal" required />
<TextField fullWidth label="Mensaje" name="message" multiline rows={4} value={formData.message} onChange={(e) => setFormData({...formData, message: e.target.value})} margin="normal" required />
<Button type="submit" fullWidth variant="contained" size="large" sx={{ mt: 3, mb: 2 }} > Enviar Mensaje </Button> </Box> </Paper> );}🧭 - Navigation App Bar
import { AppBar, Toolbar, Typography, Button, IconButton, Menu, MenuItem, Box, Avatar} from '@mui/material';import { Menu as MenuIcon, AccountCircle } from '@mui/icons-material';import { useState } from 'react';
function NavigationBar() { const [anchorEl, setAnchorEl] = useState(null);
return ( <AppBar position="sticky"> <Toolbar> <IconButton edge="start" color="inherit" sx={{ mr: 2, display: { md: 'none' } }} > <MenuIcon /> </IconButton>
<Typography variant="h6" component="div" sx={{ flexGrow: 1 }}> Mi Aplicación </Typography>
<Box sx={{ display: { xs: 'none', md: 'flex' }, gap: 2 }}> <Button color="inherit">Inicio</Button> <Button color="inherit">Productos</Button> <Button color="inherit">Contacto</Button> </Box>
<IconButton color="inherit" onClick={(e) => setAnchorEl(e.currentTarget)} > <AccountCircle /> </IconButton>
<Menu anchorEl={anchorEl} open={Boolean(anchorEl)} onClose={() => setAnchorEl(null)} > <MenuItem onClick={() => setAnchorEl(null)}>Perfil</MenuItem> <MenuItem onClick={() => setAnchorEl(null)}>Configuración</MenuItem> <MenuItem onClick={() => setAnchorEl(null)}>Cerrar Sesión</MenuItem> </Menu> </Toolbar> </AppBar> );}📚 - Stack: Componente de Layout Esencial
Stack es uno de los componentes más útiles para crear layouts flexibles y organizados:
import { Stack, Typography, Button, Avatar, Chip } from '@mui/material';
// Stack básico - vertical por defectofunction BasicStack() { return ( <Stack spacing={2} sx={{ p: 3 }}> <Typography variant="h4">Título Principal</Typography> <Typography variant="body1">Contenido del párrafo</Typography> <Button variant="contained">Acción</Button> </Stack> );}🔧 - Configuraciones de Stack
1. Dirección y Espaciado:
// Stack horizontal con diferentes espaciados<Stack direction="row" spacing={1}> <Chip label="Tag 1" /> <Chip label="Tag 2" /> <Chip label="Tag 3" /></Stack>
// Stack con espaciado responsive<Stack direction={{ xs: 'column', sm: 'row' }} spacing={{ xs: 1, sm: 2, md: 4 }}> <Button variant="outlined">Opción 1</Button> <Button variant="outlined">Opción 2</Button> <Button variant="outlined">Opción 3</Button></Stack>2. Alineación y Distribución:
// Stack con alineación personalizada<Stack direction="row" spacing={2} alignItems="center" justifyContent="space-between" sx={{ width: '100%', p: 2 }}> <Typography variant="h6">Logo</Typography> <Stack direction="row" spacing={1}> <Button>Login</Button> <Button variant="contained">Sign Up</Button> </Stack></Stack>3. Dividers Automáticos:
import { Stack, Typography, Divider } from '@mui/material';
<Stack spacing={2} divider={<Divider orientation="horizontal" flexItem />} sx={{ p: 2 }}> <Typography>Sección 1</Typography> <Typography>Sección 2</Typography> <Typography>Sección 3</Typography></Stack>
// Dividers verticales<Stack direction="row" spacing={2} divider={<Divider orientation="vertical" flexItem />}> <Typography>Item 1</Typography> <Typography>Item 2</Typography> <Typography>Item 3</Typography></Stack>🛠️ - Herramientas y Recursos Útiles
🎨 - Generadores y Herramientas de Diseño
Theme Creator & Customization:
💡 - Recomendaciones
- Utilizar sx sobre la propiedad style.
- Realizar un diseño y configuración del Theme previamente para tener una base sólida al momento de crear componentes.
- Crear variantes de componentes para maximizar escalabilidad.
Performance y Optimización: