그리드

그리드 (Grid)

반응형 레이아웃 그리드는 화면 크기와 방향에 맞춰 조정되므로, 레이아웃 전반에 걸쳐 일관성을 보장해요.

Grid 컴포넌트는 열(column)의 개수가 정해진 레이아웃에 잘 맞아요. 각 자식의 열 점유 폭(column span)을 지정하기 위해 여러 브레이크포인트로 열을 구성할 수 있어요.

출처: 문서

본문

반응형 레이아웃 그리드는 화면 크기와 방향에 맞춰 조정되므로, 레이아웃 전반에 걸쳐 일관성을 보장해요.

Grid 컴포넌트는 열의 개수가 정해진 레이아웃에 잘 맞아요. 각 자식의 열 점유 폭을 지정하기 위해 여러 브레이크포인트로 열을 구성할 수 있어요.

작동 방식 (How it works)

그리드 시스템은 Grid 컴포넌트로 구현돼요:

  • 높은 유연성을 위해 CSS Grid가 아닌 CSS Flexbox를 사용해요.
  • 그리드는 항상 flex item이에요. container prop을 사용해 flex 컨테이너를 추가해요.
  • 아이템 너비는 백분율로 설정되므로 항상 유동적이며 부모 요소에 상대적인 크기로 조정돼요.
  • 기본 그리드 브레이크포인트는 xs, sm, md, lg, xl의 다섯 가지예요. 커스텀 브레이크포인트가 필요하다면 커스텀 브레이크포인트 그리드를 확인하세요.
  • 각 브레이크포인트에 정수 값을 주어, 뷰포트 너비가 브레이크포인트 제약을 충족할 때 컴포넌트가 12개 열 중 몇 개를 차지할지 지정할 수 있어요.
  • 아이템 사이 간격을 추가하기 위해 the gap CSS property를 사용해요.
  • 행 걸침(row spanning) 을 지원하지 않아요. 자식 요소는 여러 행에 걸칠 수 없어요. 이 기능이 필요하다면 CSS Grid를 사용할 것을 권장해요.
  • 자식을 자동으로 배치하지 않아요. 자식을 하나씩 맞추려고 시도하고, 공간이 충분하지 않으면 나머지 자식들은 다음 줄에서 시작해요. 자동 배치가 필요하다면 CSS Grid를 사용할 것을 권장해요.

:::warning Grid 컴포넌트는 레이아웃 그리드이지 데이터 그리드가 아니에요. 데이터 그리드가 필요하다면 MUI X DataGrid 컴포넌트를 확인하세요. :::

유동 그리드 (Fluid grids)

유동 그리드는 콘텐츠를 확장·축소하는 열을 사용해요. 유동 그리드의 레이아웃은 레이아웃을 크게 변경해야 하는지 결정하기 위해 브레이크포인트를 사용할 수 있어요.

기본 그리드 (Basic grid)

그리드 레이아웃을 만들려면 컨테이너가 필요해요. container prop을 사용해 그리드 아이템(Grid는 항상 아이템이에요)을 감싸는 그리드 컨테이너를 만드세요.

열 너비는 1에서 12 사이의 정수 값이에요. 예를 들어 size={6}인 아이템은 그리드 컨테이너 너비의 절반을 차지해요.

import { styled } from '@mui/material/styles';
import Box from '@mui/material/Box';
import Paper from '@mui/material/Paper';
import Grid from '@mui/material/Grid';

const Item = styled(Paper)(({ theme }) => ({
  backgroundColor: '#fff',
  ...theme.typography.body2,
  padding: theme.spacing(1),
  textAlign: 'center',
  color: (theme.vars ?? theme).palette.text.secondary,
  ...theme.applyStyles('dark', {
    backgroundColor: '#1A2027',
  }),
}));

export default function BasicGrid() {
  return (
    <Box sx={{ flexGrow: 1 }}>
      <Grid container spacing={2}>
        <Grid size={8}>
          <Item>size=8</Item>
        </Grid>
        <Grid size={4}>
          <Item>size=4</Item>
        </Grid>
        <Grid size={4}>
          <Item>size=4</Item>
        </Grid>
        <Grid size={8}>
          <Item>size=8</Item>
        </Grid>
      </Grid>
    </Box>
  );
}

여러 브레이크포인트 (Multiple breakpoints)

아이템은 여러 너비를 가질 수 있으며, 정의된 브레이크포인트에서 레이아웃이 변경돼요. 너비 값은 모든 더 넓은 브레이크포인트에 적용되고, 더 큰 브레이크포인트는 더 작은 브레이크포인트에 주어진 값을 덮어써요.

예를 들어 size={{ xs: 12, sm: 6 }}인 컴포넌트는 뷰포트가 600픽셀보다 좁을 때 전체 뷰포트 너비를 차지해요. 뷰포트가 이 크기를 넘어서면, 컴포넌트는 전체 너비의 절반 — 12개가 아닌 6개 열을 차지해요.

import { styled } from '@mui/material/styles';
import Box from '@mui/material/Box';
import Paper from '@mui/material/Paper';
import Grid from '@mui/material/Grid';

const Item = styled(Paper)(({ theme }) => ({
  backgroundColor: '#fff',
  ...theme.typography.body2,
  padding: theme.spacing(1),
  textAlign: 'center',
  color: (theme.vars ?? theme).palette.text.secondary,
  ...theme.applyStyles('dark', {
    backgroundColor: '#1A2027',
  }),
}));

export default function FullWidthGrid() {
  return (
    <Box sx={{ flexGrow: 1 }}>
      <Grid container spacing={2}>
        <Grid size={{ xs: 6, md: 8 }}>
          <Item>xs=6 md=8</Item>
        </Grid>
        <Grid size={{ xs: 6, md: 4 }}>
          <Item>xs=6 md=4</Item>
        </Grid>
        <Grid size={{ xs: 6, md: 4 }}>
          <Item>xs=6 md=4</Item>
        </Grid>
        <Grid size={{ xs: 6, md: 8 }}>
          <Item>xs=6 md=8</Item>
        </Grid>
      </Grid>
    </Box>
  );
}

간격 (Spacing)

spacing prop을 사용해 자식 사이의 공간을 제어해요. spacing 값은 양수인 어떤 숫자(소수 포함)나 문자열일 수 있어요. 이 prop은 theme.spacing() 헬퍼를 사용해 CSS 속성으로 변환돼요.

다음 데모는 spacing prop의 사용을 보여줘요:

import * as React from 'react';
import Box from '@mui/material/Box';
import Grid from '@mui/material/Grid';
import FormLabel from '@mui/material/FormLabel';
import FormControl from '@mui/material/FormControl';
import FormControlLabel from '@mui/material/FormControlLabel';
import RadioGroup from '@mui/material/RadioGroup';
import Radio from '@mui/material/Radio';
import Paper from '@mui/material/Paper';
import { HighlightedCode } from '@mui/internal-core-docs/HighlightedCode';

export default function SpacingGrid() {
  const [spacing, setSpacing] = React.useState(2);

  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setSpacing(Number((event.target as HTMLInputElement).value));
  };

  const jsx = `
<Grid container spacing={${spacing}}>
`;

  return (
    <Box
      sx={{
        flexGrow: 1,
        display: 'flex',
        flexDirection: 'column',
        gap: 2,
        pt: 2,
        '&& pre': { margin: 0 },
      }}
    >
      <Grid container sx={{ justifyContent: 'center' }} spacing={spacing}>
        {[0, 1, 2].map((value) => (
          <Grid key={value}>
            <Paper
              sx={(theme) => ({
                height: 140,
                width: 100,
                backgroundColor: '#fff',
                ...theme.applyStyles('dark', {
                  backgroundColor: '#1A2027',
                }),
              })}
            />
          </Grid>
        ))}
      </Grid>
      <Paper sx={{ p: 2 }}>
        <FormControl component="fieldset">
          <FormLabel component="legend">spacing</FormLabel>
          <RadioGroup
            name="spacing"
            aria-label="spacing"
            value={spacing.toString()}
            onChange={handleChange}
            row
          >
            {[0, 0.5, 1, 2, 3, 4, 8, 12].map((value) => (
              <FormControlLabel
                key={value}
                value={value.toString()}
                control={<Radio />}
                label={value.toString()}
              />
            ))}
          </RadioGroup>
        </FormControl>
      </Paper>
      <HighlightedCode code={jsx} language="jsx" />
    </Box>
  );
}

행·열 간격 (Row and column spacing)

rowSpacing와 columnSpacing props를 사용하면 행과 열의 간격을 개별적으로 지정할 수 있어요. 이 props는 CSS Grid의 row-gap과 column-gap 속성과 유사하게 동작해요.

import { styled } from '@mui/material/styles';
import Grid from '@mui/material/Grid';
import Paper from '@mui/material/Paper';
import Box from '@mui/material/Box';

const Item = styled(Paper)(({ theme }) => ({
  backgroundColor: '#fff',
  ...theme.typography.body2,
  padding: theme.spacing(1),
  textAlign: 'center',
  color: (theme.vars ?? theme).palette.text.secondary,
  ...theme.applyStyles('dark', {
    backgroundColor: '#1A2027',
  }),
}));

export default function RowAndColumnSpacing() {
  return (
    <Box sx={{ width: '100%' }}>
      <Grid container rowSpacing={1} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
        <Grid size={6}>
          <Item>1</Item>
        </Grid>
        <Grid size={6}>
          <Item>2</Item>
        </Grid>
        <Grid size={6}>
          <Item>3</Item>
        </Grid>
        <Grid size={6}>
          <Item>4</Item>
        </Grid>
      </Grid>
    </Box>
  );
}

반응형 값 (Responsive values)

주어진 브레이크포인트가 활성일 때 값을 변경하도록 prop 값을 설정할 수 있어요. 예를 들어, 다음 데모처럼 Material Design의 권장 반응형 레이아웃 그리드를 구현할 수 있어요:

import { styled } from '@mui/material/styles';
import Box from '@mui/material/Box';
import Paper from '@mui/material/Paper';
import Grid from '@mui/material/Grid';

const Item = styled(Paper)(({ theme }) => ({
  backgroundColor: '#fff',
  ...theme.typography.body2,
  padding: theme.spacing(2),
  textAlign: 'center',
  color: (theme.vars ?? theme).palette.text.secondary,
  ...theme.applyStyles('dark', {
    backgroundColor: '#1A2027',
  }),
}));

export default function ResponsiveGrid() {
  return (
    <Box sx={{ flexGrow: 1 }}>
      <Grid container spacing={{ xs: 2, md: 3 }} columns={{ xs: 4, sm: 8, md: 12 }}>
        {Array.from(Array(6)).map((_, index) => (
          <Grid key={index} size={{ xs: 2, sm: 4, md: 4 }}>
            <Item>{index + 1}</Item>
          </Grid>
        ))}
      </Grid>
    </Box>
  );
}

반응형 값은 다음 항목에서 지원돼요:

  • size
  • columns
  • columnSpacing
  • direction
  • rowSpacing
  • spacing
  • offset

인터랙티브 (Interactive)

다음은 다양한 설정의 시각적 결과를 탐색해볼 수 있는 인터랙티브 데모예요:

import * as React from 'react';
import Grid, { GridDirection } from '@mui/material/Grid';
import FormControl from '@mui/material/FormControl';
import FormLabel from '@mui/material/FormLabel';
import FormControlLabel from '@mui/material/FormControlLabel';
import RadioGroup from '@mui/material/RadioGroup';
import Radio from '@mui/material/Radio';
import Paper from '@mui/material/Paper';
import { HighlightedCode } from '@mui/internal-core-docs/HighlightedCode';

type GridItemsAlignment =
  'flex-start' | 'center' | 'flex-end' | 'stretch' | 'baseline';

type GridJustification =
  | 'flex-start'
  | 'center'
  | 'flex-end'
  | 'space-between'
  | 'space-around'
  | 'space-evenly';

export default function InteractiveGrid() {
  const [direction, setDirection] = React.useState<GridDirection>('row');
  const [justifyContent, setJustifyContent] =
    React.useState<GridJustification>('center');
  const [alignItems, setAlignItems] = React.useState<GridItemsAlignment>('center');

  const jsx = `
<Grid
  container
  direction="${direction}"
  sx={{
    justifyContent: "${justifyContent}",
    alignItems: "${alignItems}",
  }}
>
`;

  return (
    <Grid sx={{ flexGrow: 1 }} container>
      <Grid size={12}>
        <Grid
          container
          spacing={2}
          direction={direction}
          sx={{ alignItems, justifyContent, height: 300, pb: 2 }}
        >
          {[0, 1, 2].map((value) => (
            <Grid key={value}>
              <Paper
                sx={(theme) => ({
                  p: 2,
                  backgroundColor: '#fff',
                  height: '100%',
                  color: 'text.secondary',
                  pt: `${(value + 1) * 10}px`,
                  pb: `${(value + 1) * 10}px`,
                  ...theme.applyStyles('dark', {
                    backgroundColor: '#1A2027',
                  }),
                })}
              >
                {`Cell ${value + 1}`}
              </Paper>
            </Grid>
          ))}
        </Grid>
      </Grid>
      <Grid size={12}>
        <Paper sx={{ p: 2 }}>
          <Grid container spacing={3}>
            <Grid size={12}>
              <FormControl component="fieldset">
                <FormLabel component="legend">direction</FormLabel>
                <RadioGroup
                  row
                  name="direction"
                  aria-label="direction"
                  value={direction}
                  onChange={(event) => {
                    setDirection(
                      (event.target as HTMLInputElement).value as GridDirection,
                    );
                  }}
                >
                  <FormControlLabel value="row" control={<Radio />} label="row" />
                  <FormControlLabel
                    value="row-reverse"
                    control={<Radio />}
                    label="row-reverse"
                  />
                </RadioGroup>
              </FormControl>
            </Grid>
            <Grid size={12}>
              <FormControl component="fieldset">
                <FormLabel component="legend">justifyContent</FormLabel>
                <RadioGroup
                  row
                  name="justifyContent"
                  aria-label="justifyContent"
                  value={justifyContent}
                  onChange={(event) => {
                    setJustifyContent(
                      (event.target as HTMLInputElement).value as GridJustification,
                    );
                  }}
                >
                  <FormControlLabel
                    value="flex-start"
                    control={<Radio />}
                    label="flex-start"
                  />
                  <FormControlLabel
                    value="center"
                    control={<Radio />}
                    label="center"
                  />
                  <FormControlLabel
                    value="flex-end"
                    control={<Radio />}
                    label="flex-end"
                  />
                  <FormControlLabel
                    value="space-between"
                    control={<Radio />}
                    label="space-between"
                  />
                  <FormControlLabel
                    value="space-around"
                    control={<Radio />}
                    label="space-around"
                  />
                  <FormControlLabel
                    value="space-evenly"
                    control={<Radio />}
                    label="space-evenly"
                  />
                </RadioGroup>
              </FormControl>
            </Grid>
            <Grid size={12}>
              <FormControl component="fieldset">
                <FormLabel component="legend">alignItems</FormLabel>
                <RadioGroup
                  row
                  name="alignItems"
                  aria-label="align items"
                  value={alignItems}
                  onChange={(event) => {
                    setAlignItems(
                      (event.target as HTMLInputElement).value as GridItemsAlignment,
                    );
                  }}
                >
                  <FormControlLabel
                    value="flex-start"
                    control={<Radio />}
                    label="flex-start"
                  />
                  <FormControlLabel
                    value="center"
                    control={<Radio />}
                    label="center"
                  />
                  <FormControlLabel
                    value="flex-end"
                    control={<Radio />}
                    label="flex-end"
                  />
                  <FormControlLabel
                    value="stretch"
                    control={<Radio />}
                    label="stretch"
                  />
                  <FormControlLabel
                    value="baseline"
                    control={<Radio />}
                    label="baseline"
                  />
                </RadioGroup>
              </FormControl>
            </Grid>
          </Grid>
        </Paper>
      </Grid>
      <Grid size={12}>
        <HighlightedCode code={jsx} language="jsx" />
      </Grid>
    </Grid>
  );
}

자동 레이아웃 (Auto-layout)

자동 레이아웃 기능은 존재하는 모든 아이템에 동일한 공간을 부여해요. 한 아이템의 너비를 설정하면 나머지 아이템들은 그에 맞춰 자동으로 크기가 조정돼요.

import { styled } from '@mui/material/styles';
import Box from '@mui/material/Box';
import Paper from '@mui/material/Paper';
import Grid from '@mui/material/Grid';

const Item = styled(Paper)(({ theme }) => ({
  backgroundColor: '#fff',
  ...theme.typography.body2,
  padding: theme.spacing(1),
  textAlign: 'center',
  color: (theme.vars ?? theme).palette.text.secondary,
  ...theme.applyStyles('dark', {
    backgroundColor: '#1A2027',
  }),
}));

export default function AutoGrid() {
  return (
    <Box sx={{ flexGrow: 1 }}>
      <Grid container spacing={3}>
        <Grid size="grow">
          <Item>size=grow</Item>
        </Grid>
        <Grid size={6}>
          <Item>size=6</Item>
        </Grid>
        <Grid size="grow">
          <Item>size=grow</Item>
        </Grid>
      </Grid>
    </Box>
  );
}

가변 너비 콘텐츠 (Variable width content)

브레이크포인트 값이 "auto"로 주어지면, 열의 크기가 콘텐츠의 너비에 맞춰 자동으로 조정돼요. 아래 데모는 이것이 어떻게 동작하는지 보여줘요:

import { styled } from '@mui/material/styles';
import Box from '@mui/material/Box';
import Paper from '@mui/material/Paper';
import Grid from '@mui/material/Grid';

const Item = styled(Paper)(({ theme }) => ({
  backgroundColor: '#fff',
  ...theme.typography.body2,
  padding: theme.spacing(1),
  textAlign: 'center',
  color: (theme.vars ?? theme).palette.text.secondary,
  ...theme.applyStyles('dark', {
    backgroundColor: '#1A2027',
  }),
}));

export default function VariableWidthGrid() {
  return (
    <Box sx={{ flexGrow: 1 }}>
      <Grid container spacing={3}>
        <Grid size="auto">
          <Item>size=auto</Item>
        </Grid>
        <Grid size={6}>
          <Item>size=6</Item>
        </Grid>
        <Grid size="grow">
          <Item>size=grow</Item>
        </Grid>
      </Grid>
    </Box>
  );
}

중첩 그리드 (Nested grid)

다른 그리드 컨테이너 안의 직접 자식으로 렌더링되는 그리드 컨테이너는, 최상위에서 columns와 spacing을 상속받는 중첩 그리드예요. 그리고 해당 props를 받으면 최상위 그리드의 props도 상속받아요.

:::success

중첩 그리드 컨테이너는 다른 그리드 컨테이너의 직접 자식이어야 한다는 점을 유의하세요. 사이에 그리드가 아닌 요소가 있으면, 그리드 컨테이너는 새로운 루트 컨테이너로 시작해요.

<Grid container>
  <Grid container> // A nested grid container that inherits columns and spacing from above.
    <div>
      <Grid container> // A new root grid container with its own variables scope.

:::

간격 상속 (Inheriting spacing)

중첩 그리드 컨테이너는 인스턴스에 spacing prop이 지정되지 않는 한 부모로부터 행·열 간격을 상속해요.

import { styled } from '@mui/material/styles';
import Box from '@mui/material/Box';
import Paper from '@mui/material/Paper';
import Grid from '@mui/material/Grid';

const Item = styled(Paper)(({ theme }) => ({
  backgroundColor: '#fff',
  ...theme.typography.body2,
  padding: theme.spacing(1),
  textAlign: 'center',
  color: (theme.vars ?? theme).palette.text.secondary,
  ...theme.applyStyles('dark', {
    backgroundColor: '#1A2027',
  }),
}));

export default function NestedGrid() {
  return (
    <Box sx={{ flexGrow: 1 }}>
      <Grid container spacing={2}>
        <Grid size={{ xs: 12, md: 5, lg: 4 }}>
          <Item>Email subscribe section</Item>
        </Grid>
        <Grid container spacing={4} size={{ xs: 12, md: 7, lg: 8 }}>
          <Grid size={{ xs: 6, lg: 3 }}>
            <Item>
              <Box
                id="category-a"
                sx={{ fontSize: '12px', textTransform: 'uppercase' }}
              >
                Category A
              </Box>
              <Box component="ul" aria-labelledby="category-a" sx={{ pl: 2 }}>
                <li>Link 1.1</li>
                <li>Link 1.2</li>
                <li>Link 1.3</li>
              </Box>
            </Item>
          </Grid>
          <Grid size={{ xs: 6, lg: 3 }}>
            <Item>
              <Box
                id="category-b"
                sx={{ fontSize: '12px', textTransform: 'uppercase' }}
              >
                Category B
              </Box>
              <Box component="ul" aria-labelledby="category-b" sx={{ pl: 2 }}>
                <li>Link 2.1</li>
                <li>Link 2.2</li>
                <li>Link 2.3</li>
              </Box>
            </Item>
          </Grid>
          <Grid size={{ xs: 6, lg: 3 }}>
            <Item>
              <Box
                id="category-c"
                sx={{ fontSize: '12px', textTransform: 'uppercase' }}
              >
                Category C
              </Box>
              <Box component="ul" aria-labelledby="category-c" sx={{ pl: 2 }}>
                <li>Link 3.1</li>
                <li>Link 3.2</li>
                <li>Link 3.3</li>
              </Box>
            </Item>
          </Grid>
          <Grid size={{ xs: 6, lg: 3 }}>
            <Item>
              <Box
                id="category-d"
                sx={{ fontSize: '12px', textTransform: 'uppercase' }}
              >
                Category D
              </Box>
              <Box component="ul" aria-labelledby="category-d" sx={{ pl: 2 }}>
                <li>Link 4.1</li>
                <li>Link 4.2</li>
                <li>Link 4.3</li>
              </Box>
            </Item>
          </Grid>
        </Grid>
        <Grid
          container
          sx={{
            justifyContent: 'space-between',
            alignItems: 'center',
            flexDirection: { xs: 'column', sm: 'row' },
            fontSize: '12px',
          }}
          size={12}
        >
          <Grid sx={{ order: { xs: 2, sm: 1 } }}>
            <Item>© Copyright</Item>
          </Grid>
          <Grid container columnSpacing={1} sx={{ order: { xs: 1, sm: 2 } }}>
            <Grid>
              <Item>Link A</Item>
            </Grid>
            <Grid>
              <Item>Link B</Item>
            </Grid>
            <Grid>
              <Item>Link C</Item>
            </Grid>
          </Grid>
        </Grid>
      </Grid>
    </Box>
  );
}

열 상속 (Inheriting columns)

중첩 그리드 컨테이너는 인스턴스에 columns prop이 지정되지 않는 한 부모로부터 열을 상속해요.

import { styled } from '@mui/material/styles';
import Box from '@mui/material/Box';
import Paper from '@mui/material/Paper';
import Grid from '@mui/material/Grid';

const Item = styled(Paper)(({ theme }) => ({
  backgroundColor: '#fff',
  ...theme.typography.body2,
  padding: theme.spacing(1),
  textAlign: 'center',
  color: (theme.vars ?? theme).palette.text.secondary,
  ...theme.applyStyles('dark', {
    backgroundColor: '#1A2027',
  }),
}));

export default function NestedGridColumns() {
  return (
    <Box sx={{ flexGrow: 1 }}>
      <Grid container spacing={2} columns={24}>
        <Grid size={8}>
          <Item>size=8/24</Item>
        </Grid>
        <Grid container size={16}>
          <Grid size={12}>
            <Item>nested size=12/24</Item>
          </Grid>
          <Grid size={12}>
            <Item>nested size=12/24</Item>
          </Grid>
        </Grid>
        <Grid size={8}>
          <Item>size=8/24</Item>
        </Grid>
        <Grid container columns={12} size={16}>
          <Grid size={6}>
            <Item>nested size=6/12</Item>
          </Grid>
          <Grid size={6}>
            <Item>nested size=6/12</Item>
          </Grid>
        </Grid>
      </Grid>
    </Box>
  );
}

열 (Columns)

columns prop을 사용해 그리드의 기본 열 수(12)를 변경할 수 있어요:

import { styled } from '@mui/material/styles';
import Box from '@mui/material/Box';
import Paper from '@mui/material/Paper';
import Grid from '@mui/material/Grid';

const Item = styled(Paper)(({ theme }) => ({
  backgroundColor: '#fff',
  ...theme.typography.body2,
  padding: theme.spacing(1),
  textAlign: 'center',
  color: (theme.vars ?? theme).palette.text.secondary,
  ...theme.applyStyles('dark', {
    backgroundColor: '#1A2027',
  }),
}));

export default function ColumnsGrid() {
  return (
    <Box sx={{ flexGrow: 1 }}>
      <Grid container spacing={2} columns={16}>
        <Grid size={8}>
          <Item>size=8</Item>
        </Grid>
        <Grid size={8}>
          <Item>size=8</Item>
        </Grid>
      </Grid>
    </Box>
  );
}

오프셋 (Offset)

offset prop은 아이템을 그리드의 오른쪽으로 밀어요. 이 prop은 다음을 받아요:

  • 숫자 — 예를 들어 offset={{ md: 2 }}는 뷰포트 크기가 md 브레이크포인트 이상일 때 아이템을 오른쪽으로 두 열 밀어요.
  • "auto" — 아이템을 그리드 컨테이너의 맨 오른쪽으로 밀어요.

아래 데모는 offset props를 사용하는 방법을 보여줘요:

import { styled } from '@mui/material/styles';
import Paper from '@mui/material/Paper';
import Grid from '@mui/material/Grid';

const Item = styled(Paper)(({ theme }) => ({
  backgroundColor: '#fff',
  ...theme.typography.body2,
  padding: theme.spacing(1),
  textAlign: 'center',
  color: (theme.vars ?? theme).palette.text.secondary,
  ...theme.applyStyles('dark', {
    backgroundColor: '#1A2027',
  }),
}));

export default function OffsetGrid() {
  return (
    <Grid container spacing={3} sx={{ flexGrow: 1 }}>
      <Grid size={{ xs: 6, md: 2 }} offset={{ xs: 3, md: 0 }}>
        <Item>1</Item>
      </Grid>
      <Grid size={{ xs: 4, md: 2 }} offset={{ md: 'auto' }}>
        <Item>2</Item>
      </Grid>
      <Grid size={{ xs: 4, md: 2 }} offset={{ xs: 4, md: 0 }}>
        <Item>3</Item>
      </Grid>
      <Grid size={{ xs: 'grow', md: 6 }} offset={{ md: 2 }}>
        <Item>4</Item>
      </Grid>
    </Grid>
  );
}

커스텀 브레이크포인트 (Custom breakpoints)

테마에 커스텀 브레이크포인트를 지정하면, 그 이름들을 반응형 값의 그리드 아이템 prop으로 사용할 수 있어요:

import { ThemeProvider, createTheme } from '@mui/material/styles';

function Demo() {
  return (
    <ThemeProvider
      theme={createTheme({
        breakpoints: {
          values: {
            laptop: 1024,
            tablet: 640,
            mobile: 0,
            desktop: 1280,
          },
        },
      })}
    >
      <Grid container spacing={{ mobile: 1, tablet: 2, laptop: 3 }}>
        {Array.from(Array(4)).map((_, index) => (
          <Grid key={index} size={{ mobile: 6, tablet: 4, laptop: 3 }}>
            <div>{index + 1}</div>
          </Grid>
        ))}
      </Grid>
    </ThemeProvider>
  );
}

:::info 커스텀 브레이크포인트는 모든 반응형 값에 영향을 미쳐요. :::

TypeScript

테마 브레이크포인트 인터페이스에 모듈 확장(module augmentation)을 설정해야 해요.

declare module '@mui/system' {
  interface BreakpointOverrides {
    // Your custom breakpoints
    laptop: true;
    tablet: true;
    mobile: true;
    desktop: true;
    // Remove default breakpoints
    xs: false;
    sm: false;
    md: false;
    lg: false;
    xl: false;
  }
}

커스터마이즈 (Customization)

중앙 정렬 요소 (Centered elements)

그리드 아이템의 콘텐츠를 중앙에 정렬하려면 아이템에 직접 display="flex"를 지정하세요. 그런 다음 justifyContent 및/또는 alignItems를 사용해 콘텐츠의 위치를 조정하세요:

import Avatar from '@mui/material/Avatar';
import Box from '@mui/material/Box';
import Grid from '@mui/material/Grid';

export default function CenteredElementGrid() {
  return (
    <Box sx={{ flexGrow: 1 }}>
      <Grid container spacing={2} sx={{ minHeight: 160 }}>
        <Grid
          sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}
          size="grow"
        >
          <Avatar src="/static/images/avatar/1.jpg" />
        </Grid>
        <Grid
          sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}
        >
          <Avatar src="/static/images/avatar/2.jpg" />
        </Grid>
        <Grid
          sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}
          size="grow"
        >
          <Avatar src="/static/images/avatar/3.jpg" />
        </Grid>
      </Grid>
    </Box>
  );
}

:::warning 이 상황에서 container prop을 사용하는 것은 동작하지 않아요. 그리드 컨테이너는 오직 그리드 아이템을 감싸도록 설계되었기 때문이에요. 다른 요소를 감쌀 수 없어요. :::

전체 테두리 (Full border)

import Box from '@mui/material/Box';
import Grid from '@mui/material/Grid';

export default function FullBorderedGrid() {
  return (
    <Box sx={{ flexGrow: 1, p: 2 }}>
      <Grid
        container
        sx={{
          '--Grid-borderWidth': '1px',
          borderTop: 'var(--Grid-borderWidth) solid',
          borderLeft: 'var(--Grid-borderWidth) solid',
          borderColor: 'divider',
          '& > div': {
            borderRight: 'var(--Grid-borderWidth) solid',
            borderBottom: 'var(--Grid-borderWidth) solid',
            borderColor: 'divider',
          },
        }}
      >
        {[...Array(6)].map((_, index) => (
          <Grid
            key={index}
            size={{
              xs: 12,
              sm: 6,
              md: 4,
              lg: 3,
            }}
            sx={{ minHeight: 160 }}
          />
        ))}
      </Grid>
    </Box>
  );
}

반쪽 테두리 (Half border)

import Box from '@mui/material/Box';
import Grid from '@mui/material/Grid';

export default function HalfBorderedGrid() {
  const colWidth = { xs: 12, sm: 6, md: 4, lg: 3 } as const;
  return (
    <Box sx={{ flexGrow: 1, p: 2 }}>
      <Grid
        container
        sx={(theme) => ({
          '--Grid-borderWidth': '1px',
          borderTop: 'var(--Grid-borderWidth) solid',
          borderColor: 'divider',
          '& > div': {
            borderRight: 'var(--Grid-borderWidth) solid',
            borderBottom: 'var(--Grid-borderWidth) solid',
            borderColor: 'divider',
            ...(Object.keys(colWidth) as Array<keyof typeof colWidth>).reduce(
              (result, key) => ({
                ...result,
                [`&:nth-of-type(${12 / colWidth[key]}n)`]: {
                  [theme.breakpoints.only(key)]: {
                    borderRight: 'none',
                  },
                },
              }),
              {},
            ),
          },
        })}
      >
        {[...Array(6)].map((_, index) => (
          <Grid key={index} size={colWidth} sx={{ minHeight: 160 }} />
        ))}
      </Grid>
    </Box>
  );
}

제한 사항 (Limitations)

열 방향 (Column direction)

direction="column" 또는 direction="column-reverse" 사용은 지원되지 않아요. Grid 컴포넌트는 레이아웃을 열로, 행이 아닌 방향으로 세분화하도록 특별히 설계됐어요. Grid 컴포넌트를 단독으로 사용해 레이아웃 요소를 세로로 쌓지 마세요. 대신, 아래처럼 Grid 안에서 Stack 컴포넌트를 사용해 세로 레이아웃을 만드세요:

import { styled } from '@mui/material/styles';
import Box from '@mui/material/Box';
import Paper from '@mui/material/Paper';
import Grid from '@mui/material/Grid';
import Stack from '@mui/material/Stack';

const Item = styled(Paper)(({ theme }) => ({
  backgroundColor: '#fff',
  ...theme.typography.body2,
  padding: theme.spacing(1),
  textAlign: 'center',
  color: (theme.vars ?? theme).palette.text.secondary,
  ...theme.applyStyles('dark', {
    backgroundColor: '#1A2027',
  }),
}));

export default function ColumnLayoutInsideGrid() {
  return (
    <Box sx={{ flexGrow: 1 }}>
      <Grid container spacing={2}>
        <Grid size={4}>
          <Stack spacing={2}>
            <Item>Column 1 - Row 1</Item>
            <Item>Column 1 - Row 2</Item>
            <Item>Column 1 - Row 3</Item>
          </Stack>
        </Grid>
        <Grid size={8}>
          <Item sx={{ height: '100%', boxSizing: 'border-box' }}>Column 2</Item>
        </Grid>
      </Grid>
    </Box>
  );
}

Grid API

데모 (Demos)

이 React 컴포넌트 사용에 대한 예제와 세부 사항은 컴포넌트 데모 페이지를 확인하세요:

Import

import Grid from '@mui/material/Grid';
// or
import { Grid } from '@mui/material';

Props

Name Type Default Required Description
children node - No
columns Array<number> | number | object 12 No
columnSpacing Array<number | string> | number | object | string - No
container bool false No
direction 'row-reverse' | 'row' | Array<'row-reverse' | 'row'> | object 'row' No
offset string | number | Array<string | number> | object - No
rowSpacing Array<number | string> | number | object | string - No
size string | bool | number | Array<string | bool | number> | object - No
spacing Array<number | string> | number | object | string 0 No
wrap 'nowrap' | 'wrap-reverse' | 'wrap' 'wrap' No

Note: The ref is forwarded to the root element (HTMLElement).

Any other props supplied will be provided to the root element (native element).

Theme default props

MuiGrid을 사용해 테마로 이 컴포넌트의 기본 props를 변경할 수 있어요.

CSS

Rule name

Global class Rule name Description
- container Styles applied to the root element if container={true}.
- root Styles applied to the root element.

Source code

이 페이지에서 정보를 찾지 못했다면, 컴포넌트 구현을 살펴보고 더 자세한 내용을 확인해 보세요.

PigmentGrid API

데모 (Demos)

이 React 컴포넌트 사용에 대한 예제와 세부 사항은 컴포넌트 데모 페이지를 확인하세요:

Import

import PigmentGrid from '@mui/material/PigmentGrid';
// or
import { PigmentGrid } from '@mui/material';

Props

Name Type Default Required Description
children node - No
columns Array<number> | number | object 12 No
columnSpacing Array<number | string> | number | object | string - No
container bool false No
direction 'row' | 'row-reverse' | Array<'row' | 'row-reverse'> | object 'row' No
offset Array<number> | number | object - No
rowSpacing Array<number | string> | number | object | string - No
size Array<number> | number | object - No
spacing Array<number | string> | number | object | string 0 No
wrap 'nowrap' | 'wrap-reverse' | 'wrap' 'wrap' No

Note: The ref is forwarded to the root element.

Source code

이 페이지에서 정보를 찾지 못했다면, 컴포넌트 구현을 살펴보고 더 자세한 내용을 확인해 보세요.

더 알아보기 (Learn more)