본문으로 건너뛰기 MUI (Material UI) Complete Guide

MUI (Material UI) Complete Guide

MUI (Material UI) Complete Guide

이 글의 핵심

MUI (formerly Material UI) is the most popular React component library ??90K+ GitHub stars, 3M weekly downloads. This guide covers MUI v6 from setup to custom themes and production patterns.

What This Guide Covers

MUI v6 provides a complete React component library with consistent design, full TypeScript support, and deep customization. This guide covers the essential components, theming, and patterns for building production UIs.

Real-world insight: Using MUI’s DataGrid cut a complex sortable/filterable table feature from 3 weeks of custom development to 2 hours of configuration.


Installation

npm install @mui/material @emotion/react @emotion/styled
npm install @mui/icons-material  # optional: 2000+ icons

1. Basic Components

Button

import Button from '@mui/material/Button'

<Button variant="contained">Primary</Button>
<Button variant="outlined">Secondary</Button>
<Button variant="text">Text</Button>

<Button variant="contained" color="error" size="large">
  Delete
</Button>

<Button variant="contained" startIcon={<DeleteIcon />} disabled>
  Disabled
</Button>

TextField (Form Input)

import TextField from '@mui/material/TextField'

<TextField label="Email" type="email" fullWidth required />

<TextField
  label="Password"
  type="password"
  error={!!errors.password}
  helperText={errors.password?.message}
  fullWidth
/>

<TextField
  label="Bio"
  multiline
  rows={4}
  fullWidth
  placeholder="Tell us about yourself"
/>

Card

import Card from '@mui/material/Card'
import CardContent from '@mui/material/CardContent'
import CardActions from '@mui/material/CardActions'

<Card sx={{ maxWidth: 400 }}>
  <CardMedia component="img" height="200" image="/cover.jpg" alt="cover" />
  <CardContent>
    <Typography variant="h5" component="h2">Card Title</Typography>
    <Typography variant="body2" color="text.secondary">
      Description text here
    </Typography>
  </CardContent>
  <CardActions>
    <Button size="small">Learn More</Button>
    <Button size="small" color="error">Delete</Button>
  </CardActions>
</Card>

2. Layout Components

Stack (Flexbox)

import Stack from '@mui/material/Stack'

<Stack direction="row" spacing={2} alignItems="center" justifyContent="space-between">
  <Typography>Left</Typography>
  <Button>Right</Button>
</Stack>

<Stack spacing={3}>
  <TextField label="Name" />
  <TextField label="Email" />
  <Button variant="contained">Submit</Button>
</Stack>

Grid (Responsive Layout)

import Grid from '@mui/material/Grid'

<Grid container spacing={3}>
  <Grid size={{ xs: 12, sm: 6, md: 4 }}>
    <Card>Card 1</Card>
  </Grid>
  <Grid size={{ xs: 12, sm: 6, md: 4 }}>
    <Card>Card 2</Card>
  </Grid>
  <Grid size={{ xs: 12, sm: 12, md: 4 }}>
    <Card>Card 3</Card>
  </Grid>
</Grid>

Container

import Container from '@mui/material/Container'

<Container maxWidth="lg">
  {/* Content centered with max-width */}
</Container>

<Container maxWidth="sm">
  {/* Narrow form container */}
</Container>

3. The sx Prop

The sx prop applies styles inline using MUI’s theme tokens:

<Box
  sx={{
    p: 3,              // padding: theme.spacing(3) = 24px
    m: 2,              // margin
    mt: 4,             // margin-top
    bgcolor: 'primary.main',  // theme color
    color: 'white',
    borderRadius: 2,   // theme.shape.borderRadius * 2
    boxShadow: 3,      // theme.shadows[3]
    display: 'flex',
    alignItems: 'center',
    gap: 2,
    // Responsive
    fontSize: { xs: '1rem', md: '1.25rem' },
    // Pseudo-classes
    '&:hover': { bgcolor: 'primary.dark' },
    // Dark mode
    '.dark &': { bgcolor: 'grey.800' },
  }}
>
  Styled Box
</Box>

4. Custom Theme

// theme.ts
import { createTheme } from '@mui/material/styles'

export const theme = createTheme({
  palette: {
    primary: {
      main: '#6366f1',    // indigo
      light: '#818cf8',
      dark: '#4f46e5',
      contrastText: '#fff',
    },
    secondary: {
      main: '#ec4899',    // pink
    },
    background: {
      default: '#f8fafc',
      paper: '#ffffff',
    },
  },
  typography: {
    fontFamily: '"Inter", "Roboto", sans-serif',
    h1: { fontSize: '2.5rem', fontWeight: 700 },
    h2: { fontSize: '2rem', fontWeight: 700 },
    body1: { lineHeight: 1.7 },
  },
  shape: {
    borderRadius: 8,  // default for all components
  },
  components: {
    // Override component defaults
    MuiButton: {
      styleOverrides: {
        root: {
          textTransform: 'none',  // disable ALL_CAPS
          fontWeight: 600,
        },
        containedPrimary: {
          boxShadow: 'none',
          '&:hover': { boxShadow: 'none' },
        },
      },
      defaultProps: {
        disableElevation: true,
      },
    },
    MuiTextField: {
      defaultProps: {
        size: 'small',
        variant: 'outlined',
      },
    },
  },
})
// App.tsx
import { ThemeProvider, CssBaseline } from '@mui/material'
import { theme } from './theme'

export default function App() {
  return (
    <ThemeProvider theme={theme}>
      <CssBaseline />  {/* normalize CSS */}
      <Router />
    </ThemeProvider>
  )
}

5. Dark Mode

// useColorMode.ts
import { createTheme } from '@mui/material'
import { useState, useMemo } from 'react'

export function useColorMode() {
  const [mode, setMode] = useState<'light' | 'dark'>('light')

  const theme = useMemo(() => createTheme({
    palette: {
      mode,
      ...(mode === 'dark' ? {
        background: { default: '#0f172a', paper: '#1e293b' },
        primary: { main: '#818cf8' },
      } : {
        background: { default: '#f8fafc', paper: '#ffffff' },
        primary: { main: '#6366f1' },
      }),
    },
  }), [mode])

  const toggleMode = () => setMode(m => m === 'light' ? 'dark' : 'light')

  return { theme, mode, toggleMode }
}

// App.tsx
export default function App() {
  const { theme, mode, toggleMode } = useColorMode()
  return (
    <ThemeProvider theme={theme}>
      <CssBaseline />
      <IconButton onClick={toggleMode}>
        {mode === 'dark' ? <LightModeIcon /> : <DarkModeIcon />}
      </IconButton>
      {/* rest of app */}
    </ThemeProvider>
  )
}

6. Dialog / Modal

import { Dialog, DialogTitle, DialogContent, DialogActions } from '@mui/material'

function ConfirmDialog({ open, onClose, onConfirm, message }) {
  return (
    <Dialog open={open} onClose={onClose} maxWidth="xs" fullWidth>
      <DialogTitle>Confirm Action</DialogTitle>
      <DialogContent>
        <Typography>{message}</Typography>
      </DialogContent>
      <DialogActions>
        <Button onClick={onClose}>Cancel</Button>
        <Button onClick={onConfirm} variant="contained" color="error">
          Confirm
        </Button>
      </DialogActions>
    </Dialog>
  )
}

7. Select, Autocomplete, DatePicker

// Select
<FormControl fullWidth>
  <InputLabel>Country</InputLabel>
  <Select value={country} onChange={e => setCountry(e.target.value)} label="Country">
    <MenuItem value="kr">South Korea</MenuItem>
    <MenuItem value="us">United States</MenuItem>
    <MenuItem value="jp">Japan</MenuItem>
  </Select>
</FormControl>

// Autocomplete (searchable select)
import Autocomplete from '@mui/material/Autocomplete'

<Autocomplete
  options={['React', 'Vue', 'Angular', 'Svelte']}
  renderInput={(params) => <TextField {...params} label="Framework" />}
  onChange={(_, value) => setFramework(value)}
/>

// Date Picker (requires @mui/x-date-pickers)
import { DatePicker } from '@mui/x-date-pickers'
<DatePicker label="Start Date" value={date} onChange={setDate} />

8. DataGrid (Advanced Table)

npm install @mui/x-data-grid
import { DataGrid } from '@mui/x-data-grid'

const columns = [
  { field: 'id', headerName: 'ID', width: 70 },
  { field: 'name', headerName: 'Name', width: 150, editable: true },
  { field: 'email', headerName: 'Email', width: 200 },
  { field: 'role', headerName: 'Role', width: 120,
    type: 'singleSelect', valueOptions: ['admin', 'user', 'viewer'] },
  {
    field: 'actions',
    type: 'actions',
    getActions: ({ id }) => [
      <GridActionsCellItem icon={<EditIcon />} label="Edit" onClick={() => handleEdit(id)} />,
      <GridActionsCellItem icon={<DeleteIcon />} label="Delete" onClick={() => handleDelete(id)} />,
    ],
  },
]

<DataGrid
  rows={users}
  columns={columns}
  pageSizeOptions={[10, 25, 50]}
  checkboxSelection
  disableRowSelectionOnClick
  onRowSelectionModelChange={setSelectedIds}
  sx={{ border: 0 }}
/>

Key Takeaways

ComponentUse for
ButtonActions, CTAs
TextFieldForms, inputs
Stack / GridLayout
CardContent containers
DialogModals, confirmations
AutocompleteSearchable selects
DataGridComplex data tables
sx propQuick inline theming
createThemeGlobal design system

MUI’s strength is comprehensive coverage ??every common UI pattern has a tested, accessible component. Customize via createTheme for global control, sx for one-off adjustments, and styleOverrides in the theme for component-level defaults. The sx prop alone eliminates most need for separate CSS files.


Frequently Asked Questions (FAQ)

Q. When would I use this in practice?

A. MUI (formerly Material UI) is the most popular React component library ??90K+ GitHub stars, 3M weekly downloads. This guide covers MUI v6 from setup to custom themes and production patterns.

Q. What should I read before this?

A. Follow the previous article or related articles links at the bottom of each post to learn in sequence.

Q. Where can I study this more deeply?

A. Check cppreference and the relevant library’s official documentation. The reference links at the end of the article are also worth using.


Other articles related to this topic.


Keywords Covered in This Article (Related Search Terms)

This article covers MUI, Material UI, React, UI, TypeScript, Components.