TDD

MUI(Material-UI) 주요 컴포넌트들의 기능

lamarcK 2025. 4. 17. 23:26

Material-UI(MUI)란?

Material-UI(MUI)는 React 기반의 UI 컴포넌트 라이브러리.

Google의 Material Design을 기반으로 만들어졌으며, 미리 만들어진 다양한 컴포넌트들을 제공한다. 버튼, 입력창, 테이블 등 기본적인 UI 요소들을 바로 사용할 수 있다. 특히 테마 시스템을 통해 색상, 폰트, 간격 등을 일괄적으로 관리할 수 있어서 일관된 디자인 시스템을 구축하기 좋다.

스타일링은 sx prop을 통한 인라인 방식, styled()를 사용한 CSS-in-JS 방식, makeStyles()를 활용한 클래스 기반 방식 등 다양한 방법을 제공한다.

레이아웃 구성을 위한 12칸 그리드 시스템이 있어 반응형 디자인을 쉽게 만들 수 있고, Box나 Stack 같은 유틸리티 컴포넌트로 레이아웃 배치도 간편하다.


**1. 레이아웃 관련
<Container> 
// 내용물을 중앙 정렬하고 최대 너비 제한
// maxWidth prop으로 xs, sm, md, lg, xl 설정 가능

<Box>
// div와 비슷한 기본 레이아웃 컴포넌트
// sx prop으로 스타일링 가능
// display, flexbox 등 설정 용이

<Grid>
// 12칼럼 그리드 시스템
// 반응형 레이아웃 구성에 사용

 

**2. 입력 관련
<TextField>
// 텍스트 입력 필드
// variant="outlined" | "filled" | "standard"
// size="small" | "medium"
// multiline - 여러 줄 입력
// error - 에러 상태
// helperText - 도움말 텍스트

<Select>
// 드롭다운 선택
<MenuItem>
// Select의 옵션들

<Checkbox>
// 체크박스

<Radio>
// 라디오 버튼
**3. 버튼 관련
<Button>
// variant="text" | "contained" | "outlined"
// color="primary" | "secondary" | "error" | etc
// size="small" | "medium" | "large"

<IconButton>
// 아이콘 버튼

<ButtonGroup>
// 여러 버튼을 그룹으로
4. 테이블 관련
<TableContainer>
// 테이블을 감싸는 컨테이너

<Table>
// 테이블 컴포넌트

<TableHead>
// 테이블 헤더 영역

<TableBody>
// 테이블 본문 영역

<TableRow>
// 테이블 행

<TableCell>
// 테이블 셀
// align="left" | "center" | "right"
**5. 디스플레이 관련:
<Typography>
// 텍스트 표시용
// variant="h1" ~ "h6", "body1", "body2" 등
// component로 실제 HTML 태그 지정

<Paper>
// 카드같은 효과를 주는 컨테이너
// elevation으로 그림자 강도 조절

<Card>
// 카드 형태의 컨테이너
<CardContent>
// 카드 내용
6. 네비게이션 관련
<AppBar>
// 상단 네비게이션 바

<Drawer>
// 사이드 메뉴

<Tabs>
<Tab>
// 탭 네비게이션
7. 피드백 관련
<Dialog>
// 모달 다이얼로그

<Snackbar>
// 토스트 메시지

<CircularProgress>
// 로딩 스피너

<Alert>
// 경고, 성공 등 메시지
8. 스타일링
sx={{ 
  // 인라인 스타일링
  mt: 2,  // margin-top
  p: 3,   // padding
  display: 'flex',
  gap: 2,
  backgroundColor: 'primary.main',
  '&:hover': {
    backgroundColor: 'primary.dark'
  }
}}

MUI의 단위

Material-UI(MUI)의 주요 spacing 단위는 기본적으로 8px을 기준으로 한다.

  1. spacing 단위
  • spacing(1) = 8px
  • spacing(2) = 16px
  • spacing(3) = 24px
  • spacing(4) = 32px
  • spacing(5) = 40px
  1. 사용 예시 
  2. // margin <Box m={2}> // 16px margin 모든 방향 <Box mt={2}> // 16px margin-top <Box mb={2}> // 16px margin-bottom <Box ml={2}> // 16px margin-left <Box mr={2}> // 16px margin-right // padding도 동일 <Box p={2}> // 16px padding 모든 방향 <Box pt={2}> // 16px padding-top
  3. breakpoints (반응형)
  • xs: 0px
  • sm: 600px
  • md: 900px
  • lg: 1200px
  • xl: 1536px

MUI에서 사용되는 축약어

// padding 관련
p: 2    // padding: 16px (모든 방향)
pt: 2   // padding-top: 16px
pb: 2   // padding-bottom: 16px
pl: 2   // padding-left: 16px
pr: 2   // padding-right: 16px
px: 2   // padding-left, padding-right: 16px
py: 2   // padding-top, padding-bottom: 16px

// margin 관련
m: 2    // margin: 16px (모든 방향)
mt: 2   // margin-top: 16px
mb: 2   // margin-bottom: 16px
ml: 2   // margin-left: 16px
mr: 2   // margin-right: 16px
mx: 2   // margin-left, margin-right: 16px
my: 2   // margin-top, margin-bottom: 16px

sx prop

Material-UI에서 제공하는 인라인 스타일링을 위한 특별한 속성

  • 직접적인 CSS 작성이 가능
  • 테마 값에 접근 가능
  • 반응형 스타일 적용 가능
  • 중첩 선택자 사용 가능
// 기본 사용
<Box sx={{ margin: 2, padding: 1 }}>

// 테마 값 사용
<Box sx={{ backgroundColor: 'primary.main' }}>

// 반응형
<Box sx={{ 
  width: {
    xs: '100%',    // 모바일
    sm: '50%',     // 태블릿
    md: '33%'      // 데스크탑
  }
}}>

// 중첩 선택자
<Box sx={{
  '&:hover': {
    backgroundColor: 'gray'
  }
}}>

// 여러 속성 한번에
<Box sx={{
  display: 'flex',
  justifyContent: 'center',
  gap: 2,
  p: 3  // padding: 24px와 동일
}}>

MUI에서 제공하는 기본 색상 팔레트

**주요 색상
import { 
  red, pink, purple, deepPurple, indigo, blue, lightBlue, 
  cyan, teal, green, lightGreen, lime, yellow, amber, 
  orange, deepOrange, brown, grey, blueGrey 
} from '@mui/material/colors';
//각 색상은 50부터 900까지의 음영을 제공합니다.
**기본 색상들:
const theme = createTheme({
  palette: {
    // 빨간색 계열
    primary: {
      main: red[500],  // #f44336
    },
    // 분홍색 계열
    primary: {
      main: pink[500],  // #e91e63
    },
    // 보라색 계열
    primary: {
      main: purple[500],  // #9c27b0
    },
    // 진한 보라색
    primary: {
      main: deepPurple[500],  // #673ab7
    },
    // 파란색 계열
    primary: {
      main: blue[500],  // #2196f3
    },
    // 초록색 계열
    primary: {
      main: green[500],  // #4caf50
    },
    // 주황색 계열
    primary: {
      main: orange[500],  // #ff9800
    }
  }
});
**자주 사용되는 조합 예시:
// 파란색 + 분홍색 조합
const theme1 = createTheme({
  palette: {
    primary: {
      main: blue[700],
    },
    secondary: {
      main: pink[400],
    },
  },
});

// 보라색 + 초록색 조합
const theme2 = createTheme({
  palette: {
    primary: {
      main: purple[500],
    },
    secondary: {
      main: green[500],
    },
  },
});

// 청록색 + 주황색 조합
const theme3 = createTheme({
  palette: {
    primary: {
      main: teal[500],
    },
    secondary: {
      main: orange[500],
    },
  },
});

// 남색 + 빨간색 조합
const theme4 = createTheme({
  palette: {
    primary: {
      main: indigo[500],
    },
    secondary: {
      main: red[500],
    },
  },
});
**다크 테마 예시:
const darkTheme = createTheme({
  palette: {
    mode: 'dark',
    primary: {
      main: blue[200],  // 더 밝은 파란색
    },
    secondary: {
      main: purple[200],  // 더 밝은 보라색
    },
    background: {
      default: '#303030',
      paper: '#424242',
    },
  },
});
**상태 색상 커스터마이징:
const theme = createTheme({
  palette: {
    primary: {
      main: blue[700],
    },
    secondary: {
      main: purple[500],
    },
    error: {
      main: red[700],
    },
    warning: {
      main: orange[700],
    },
    info: {
      main: lightBlue[700],
    },
    success: {
      main: green[700],
    },
  },
});
**각 색상의 음영 단계:
50: 가장 밝은 색상
100~300: 밝은 색상
400~600: 중간 색상
700~900: 어두운 색상

 

실제 예시

"use client"; // Next.js의 클라이언트 사이드 렌더링을 명시

import Link from "next/link"; // Next.js의 페이지 간 이동을 위한 컴포넌트
import { useState } from "react"; // React의 상태 관리 Hook
import {
  Table, // 행과 열로 구성된 데이터 표시 테이블 컴포넌트
  TableBody, // 테이블의 본문 부분을 감싸는 컴포넌트
  TableCell, // 테이블의 각 데이터 셀을 나타내는 컴포넌트
  TableContainer, // 테이블을 감싸는 스크롤 가능한 컨테이너
  TableHead, // 테이블의 헤더 부분을 감싸는 컴포넌트
  TableRow, // 테이블의 가로 행을 나타내는 컴포넌트
  Paper, // 그림자와 배경색이 있는 종이 형태의 컨테이너 컴포넌트
  Button, // 사용자 상호작용을 위한 클릭 가능한 버튼
  TextField, // 사용자 텍스트 입력을 받는 입력 필드
  Container, // 컨텐츠의 최대 너비를 제한하고 중앙 정렬하는 레이아웃 컴포넌트
  Typography, // 일관된 텍스트 스타일링을 위한 텍스트 컴포넌트
  Box, // flex 레이아웃을 위한 기본 레이아웃 컴포넌트
} from "@mui/material";
import { Post } from "@/app/types"; // 게시글 타입 정의 import

// 초기 더미 데이터 배열 선언
const DUMMY_POSTS: Post[] = [
  {
    id: 1,
    title: "첫 번째 게시글",
    content: "내용입니다.",
    author: "작성자1",
    createdAt: "2024-01-10",
    views: 0,
  },
];

export default function Home() {
  const [posts, setPosts] = useState<Post[]>(DUMMY_POSTS); // 게시글 목록 상태 관리
  const [searchTerm, setSearchTerm] = useState<string>(""); // 검색어 상태 관리

  return (
    <Container maxWidth="lg"> // 최대 너비 1200px로 제한된 컨테이너
      <Typography variant="h4" component="h1" sx={{ my: 4 }}> // margin top/bottom 4단위(32px)의 h4 크기 제목
        게시판
      </Typography>

      <Box sx={{ mb: 2, display: "flex", gap: 1 }}> // margin bottom 16px, flex 레이아웃, 요소 간 간격 8px
        <TextField
          size="small" // 작은 크기의 입력 필드
          placeholder="검색어를 입력하세요" // 입력 필드의 안내 텍스트
          value={searchTerm} // 검색어 상태값
          onChange={(e) => setSearchTerm(e.target.value)} // 입력값 변경 시 상태 업데이트
        />
        <Button
          variant="contained" // 배경색이 있는 버튼 스타일
          onClick={() => {}} // 클릭 이벤트 핸들러
        >
          검색
        </Button>
      </Box>

      <TableContainer component={Paper}> // Paper 스타일이 적용된 테이블 컨테이너
        <Table> // 기본 테이블 컴포넌트
          <TableHead> // 테이블 헤더 영역
            <TableRow> // 테이블 헤더 행
              <TableCell>번호</TableCell> // 각 열의 제목 셀
              <TableCell>제목</TableCell>
              <TableCell>작성자</TableCell>
              <TableCell>작성일</TableCell>
              <TableCell>조회수</TableCell>
            </TableRow>
          </TableHead>
          <TableBody> // 테이블 본문 영역
            {posts.map((post) => ( // 게시글 배열을 순회하며 행 생성
              <TableRow key={post.id}> // 각 게시글의 행
                <TableCell>{post.id}</TableCell> // 게시글 데이터를 표시하는 셀
                <TableCell>{post.title}</TableCell>
                <TableCell>{post.author}</TableCell>
                <TableCell>{post.createdAt}</TableCell>
                <TableCell>{post.views}</TableCell>
              </TableRow>
            ))}
          </TableBody>
        </Table>
      </TableContainer>

      <Box sx={{ mt: 2, textAlign: "right" }}> // margin top 16px, 우측 정렬
        <Link href="/write"> // 글쓰기 페이지로 이동하는 링크
          <Button variant="contained">글쓰기</Button> // 배경색이 있는 버튼
        </Link>
      </Box>
    </Container>
  );
}

이 코드에서 사용된 단위

  1. spacing 단위 (MUI의 기본 단위, 1 = 8px)
  • my: 4 (margin-top과 margin-bottom: 32px)
  • mb: 2 (margin-bottom: 16px)
  • mt: 2 (margin-top: 16px)
  • gap: 1 (간격: 8px)
  1. Container 크기
  • maxWidth="lg" (large 크기, 1200px)
  1. Typography 크기
  • variant="h4" (h4 크기의 제목)
  1. TextField 크기
  • size="small" (작은 크기의 입력 필드)
  1. Box의 display 속성
  • display: "flex" (플렉스 박스 레이아웃)
  1. Box의 정렬
  • textAlign: "right" (우측 정렬)