브레드크럼

브레드크럼 (Breadcrumbs)

브레드크럼은 페이지가 사이트의 계층 구조에서 어디에 위치하는지 시각화해주는 링크 목록입니다. 상위 조상 중 어느 곳으로든 이동할 수 있게 해줘요. 현재 위치를 보여주는 이 내비게이션 패턴은 사용자가 길을 잃지 않게 도와주는 기본 요소예요.

출처: 문서

본문

브레드크럼 소개

브레드크럼은 페이지가 사이트의 계층 구조에서 어디에 위치하는지 시각화하는 링크 목록입니다. 상위 조상들 중 어느 곳으로든 탐색할 수 있게 해줍니다.

기본 브레드크럼 (Basic breadcrumbs)

import * as React from 'react';
import Typography from '@mui/material/Typography';
import Breadcrumbs from '@mui/material/Breadcrumbs';
import Link from '@mui/material/Link';

function handleClick(event: React.MouseEvent<HTMLDivElement, MouseEvent>) {
  event.preventDefault();
  console.info('You clicked a breadcrumb.');
}

export default function BasicBreadcrumbs() {
  return (
    <div role="presentation" onClick={handleClick}>
      <Breadcrumbs aria-label="breadcrumb">
        <Link underline="hover" color="inherit" href="/">
          MUI
        </Link>
        <Link
          underline="hover"
          color="inherit"
          href="/material-ui/getting-started/installation/"
        >
          Core
        </Link>
        <Typography sx={{ color: 'text.primary' }}>Breadcrumbs</Typography>
      </Breadcrumbs>
    </div>
  );
}

마지막 브레드크럼 활성화 (Active last breadcrumb)

마지막 브레드크럼을 상호작용 가능하게 유지합니다.

import * as React from 'react';
import Breadcrumbs from '@mui/material/Breadcrumbs';
import Link from '@mui/material/Link';

function handleClick(event: React.MouseEvent<HTMLDivElement, MouseEvent>) {
  event.preventDefault();
  console.info('You clicked a breadcrumb.');
}

export default function ActiveLastBreadcrumb() {
  return (
    <div role="presentation" onClick={handleClick}>
      <Breadcrumbs aria-label="breadcrumb">
        <Link underline="hover" color="inherit" href="/">
          MUI
        </Link>
        <Link
          underline="hover"
          color="inherit"
          href="/material-ui/getting-started/installation/"
        >
          Core
        </Link>
        <Link
          underline="hover"
          href="/material-ui/react-breadcrumbs/"
          aria-current="page"
          sx={{
            color: 'text.primary',
          }}
        >
          Breadcrumbs
        </Link>
      </Breadcrumbs>
    </div>
  );
}

커스텀 구분자 (Custom separator)

아래 예시에서는 문자열 구분자 두 개와 SVG 아이콘을 사용하고 있습니다.

import * as React from 'react';
import Breadcrumbs from '@mui/material/Breadcrumbs';
import Typography from '@mui/material/Typography';
import Link from '@mui/material/Link';
import Stack from '@mui/material/Stack';
import NavigateNextIcon from '@mui/icons-material/NavigateNext';

function handleClick(event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) {
  event.preventDefault();
  console.info('You clicked a breadcrumb.');
}

export default function CustomSeparator() {
  const breadcrumbs = [
    <Link underline="hover" key="1" color="inherit" href="/" onClick={handleClick}>
      MUI
    </Link>,
    <Link
      underline="hover"
      key="2"
      color="inherit"
      href="/material-ui/getting-started/installation/"
      onClick={handleClick}
    >
      Core
    </Link>,
    <Typography key="3" sx={{ color: 'text.primary' }}>
      Breadcrumb
    </Typography>,
  ];

  return (
    <Stack spacing={2}>
      <Breadcrumbs separator="›" aria-label="breadcrumb">
        {breadcrumbs}
      </Breadcrumbs>
      <Breadcrumbs separator="-" aria-label="breadcrumb">
        {breadcrumbs}
      </Breadcrumbs>
      <Breadcrumbs
        separator={<NavigateNextIcon fontSize="small" />}
        aria-label="breadcrumb"
      >
        {breadcrumbs}
      </Breadcrumbs>
    </Stack>
  );
}

아이콘이 있는 브레드크럼 (Breadcrumbs with icons)

import * as React from 'react';
import Typography from '@mui/material/Typography';
import Breadcrumbs from '@mui/material/Breadcrumbs';
import Link from '@mui/material/Link';
import HomeIcon from '@mui/icons-material/Home';
import WhatshotIcon from '@mui/icons-material/Whatshot';
import GrainIcon from '@mui/icons-material/Grain';

function handleClick(event: React.MouseEvent<HTMLDivElement, MouseEvent>) {
  event.preventDefault();
  console.info('You clicked a breadcrumb.');
}

export default function IconBreadcrumbs() {
  return (
    <div role="presentation" onClick={handleClick}>
      <Breadcrumbs aria-label="breadcrumb">
        <Link
          underline="hover"
          sx={{ display: 'flex', alignItems: 'center' }}
          color="inherit"
          href="/"
        >
          <HomeIcon sx={{ mr: 0.5 }} fontSize="inherit" />
          MUI
        </Link>
        <Link
          underline="hover"
          sx={{ display: 'flex', alignItems: 'center' }}
          color="inherit"
          href="/material-ui/getting-started/installation/"
        >
          <WhatshotIcon sx={{ mr: 0.5 }} fontSize="inherit" />
          Core
        </Link>
        <Typography
          sx={{ color: 'text.primary', display: 'flex', alignItems: 'center' }}
        >
          <GrainIcon sx={{ mr: 0.5 }} fontSize="inherit" />
          Breadcrumb
        </Typography>
      </Breadcrumbs>
    </div>
  );
}

접힌 브레드크럼 (Collapsed breadcrumbs)

import * as React from 'react';
import Breadcrumbs from '@mui/material/Breadcrumbs';
import Typography from '@mui/material/Typography';
import Link from '@mui/material/Link';

function handleClick(event: React.MouseEvent<HTMLDivElement, MouseEvent>) {
  event.preventDefault();
  console.info('You clicked a breadcrumb.');
}

export default function CollapsedBreadcrumbs() {
  return (
    <div role="presentation" onClick={handleClick}>
      <Breadcrumbs maxItems={2} aria-label="breadcrumb">
        <Link underline="hover" color="inherit" href="#">
          Home
        </Link>
        <Link underline="hover" color="inherit" href="#">
          Catalog
        </Link>
        <Link underline="hover" color="inherit" href="#">
          Accessories
        </Link>
        <Link underline="hover" color="inherit" href="#">
          New Collection
        </Link>
        <Typography sx={{ color: 'text.primary' }}>Belts</Typography>
      </Breadcrumbs>
    </div>
  );
}

메뉴로 축소하기 (Condensed with menu)

대안으로, 접힌 링크들을 드롭다운 목록에 표시하는 Menu 컴포넌트를 추가해보는 것도 고려해볼 수 있습니다.

import * as React from 'react';
import Breadcrumbs from '@mui/material/Breadcrumbs';
import Link from '@mui/material/Link';
import Menu from '@mui/material/Menu';
import MenuItem from '@mui/material/MenuItem';
import IconButton from '@mui/material/IconButton';
import MoreHorizIcon from '@mui/icons-material/MoreHoriz';

export default function CondensedWithMenu() {
  const [anchorEl, setAnchorEl] = React.useState<HTMLButtonElement | null>(null);
  const open = Boolean(anchorEl);

  const handleClick = (event: React.MouseEvent<HTMLButtonElement> | null) => {
    if (event) {
      setAnchorEl(event.currentTarget);
    }
  };

  const handleClose = () => {
    setAnchorEl(null);
  };

  return (
    <React.Fragment>
      <Menu
        anchorEl={anchorEl}
        open={open}
        onClose={handleClose}
        aria-labelledby="with-menu-demo-breadcrumbs"
      >
        <MenuItem onClick={handleClose}>Breadcrumb 2</MenuItem>
        <MenuItem onClick={handleClose}>Breadcrumb 3</MenuItem>
        <MenuItem onClick={handleClose}>Breadcrumb 4</MenuItem>
      </Menu>
      <Breadcrumbs aria-label="breadcrumbs">
        <Link color="primary" href="#condensed-with-menu">
          Breadcrumb 1
        </Link>
        <IconButton color="primary" size="small" onClick={handleClick}>
          <MoreHorizIcon />
        </IconButton>
        <Link color="primary" href="#condensed-with-menu">
          Breadcrumb 5
        </Link>
        <Link color="primary" href="#condensed-with-menu">
          Breadcrumb 6
        </Link>
      </Breadcrumbs>
    </React.Fragment>
  );
}

커스터마이징 (Customization)

컴포넌트를 커스터마이즈하는 예시입니다. 이에 대해 더 자세히 알아보려면 overrides 문서 페이지를 참고하세요.

import * as React from 'react';
import { emphasize, styled } from '@mui/material/styles';
import Breadcrumbs from '@mui/material/Breadcrumbs';
import Chip from '@mui/material/Chip';
import HomeIcon from '@mui/icons-material/Home';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';

const StyledBreadcrumb = styled(Chip)(({ theme }) => {
  return {
    backgroundColor: theme.palette.grey[100],
    height: theme.spacing(3),
    color: (theme.vars || theme).palette.text.primary,
    fontWeight: theme.typography.fontWeightRegular,
    '&:hover, &:focus': {
      backgroundColor: emphasize(theme.palette.grey[100], 0.06),
      ...theme.applyStyles('dark', {
        backgroundColor: emphasize(theme.palette.grey[800], 0.06),
      }),
    },
    '&:active': {
      boxShadow: theme.shadows[1],
      backgroundColor: emphasize(theme.palette.grey[100], 0.12),
      ...theme.applyStyles('dark', {
        backgroundColor: emphasize(theme.palette.grey[800], 0.12),
      }),
    },
    ...theme.applyStyles('dark', {
      backgroundColor: theme.palette.grey[800],
    }),
  };
}) as typeof Chip; // TypeScript only: need a type cast here because https://github.com/Microsoft/TypeScript/issues/26591

function handleClick(event: React.MouseEvent<Element, MouseEvent>) {
  event.preventDefault();
  console.info('You clicked a breadcrumb.');
}

export default function CustomizedBreadcrumbs() {
  return (
    <div role="presentation" onClick={handleClick}>
      <Breadcrumbs aria-label="breadcrumb">
        <StyledBreadcrumb
          component="a"
          href="#"
          label="Home"
          icon={<HomeIcon fontSize="small" />}
        />
        <StyledBreadcrumb component="a" href="#" label="Catalog" />
        <StyledBreadcrumb
          label="Accessories"
          deleteIcon={<ExpandMoreIcon />}
          onDelete={handleClick}
        />
      </Breadcrumbs>
    </div>
  );
}

react-router와 통합 (Integration with react-router)

import * as React from 'react';
import Box from '@mui/material/Box';
import List from '@mui/material/List';
import Link, { LinkProps } from '@mui/material/Link';
import { ListItemProps } from '@mui/material/ListItem';
import ListItemButton from '@mui/material/ListItemButton';
import Collapse from '@mui/material/Collapse';
import ListItemText from '@mui/material/ListItemText';
import Typography from '@mui/material/Typography';
import ExpandLess from '@mui/icons-material/ExpandLess';
import ExpandMore from '@mui/icons-material/ExpandMore';
import Breadcrumbs from '@mui/material/Breadcrumbs';
import {
  Link as RouterLink,
  Route,
  Routes,
  MemoryRouter,
  useLocation,
} from 'react-router';

interface ListItemLinkProps extends ListItemProps {
  to: string;
  open?: boolean;
}

const breadcrumbNameMap: { [key: string]: string } = {
  '/inbox': 'Inbox',
  '/inbox/important': 'Important',
  '/trash': 'Trash',
  '/spam': 'Spam',
  '/drafts': 'Drafts',
};

function ListItemLink(props: ListItemLinkProps) {
  const { to, open, ...other } = props;
  const primary = breadcrumbNameMap[to];

  let icon = null;
  if (open != null) {
    icon = open ? <ExpandLess /> : <ExpandMore />;
  }

  return (
    <li>
      <ListItemButton component={RouterLink as any} to={to} {...other}>
        <ListItemText primary={primary} />
        {icon}
      </ListItemButton>
    </li>
  );
}

interface LinkRouterProps extends LinkProps {
  to: string;
  replace?: boolean;
}

function LinkRouter(props: LinkRouterProps) {
  return <Link {...props} component={RouterLink as any} />;
}

function Page() {
  const location = useLocation();
  const pathnames = location.pathname.split('/').filter((x) => x);

  return (
    <Breadcrumbs aria-label="breadcrumb">
      <LinkRouter underline="hover" color="inherit" to="/">
        Home
      </LinkRouter>
      {pathnames.map((value, index) => {
        const last = index === pathnames.length - 1;
        const to = `/${pathnames.slice(0, index + 1).join('/')}`;

        return last ? (
          <Typography key={to} sx={{ color: 'text.primary' }}>
            {breadcrumbNameMap[to]}
          </Typography>
        ) : (
          <LinkRouter underline="hover" color="inherit" to={to} key={to}>
            {breadcrumbNameMap[to]}
          </LinkRouter>
        );
      })}
    </Breadcrumbs>
  );
}

export default function RouterBreadcrumbs() {
  const [open, setOpen] = React.useState(true);

  const handleClick = () => {
    setOpen((prevOpen) => !prevOpen);
  };

  return (
    <MemoryRouter initialEntries={['/inbox']} initialIndex={0}>
      <Box sx={{ display: 'flex', flexDirection: 'column', width: 360 }}>
        <Routes>
          <Route path="*" element={<Page />} />
        </Routes>
        <Box
          sx={{ bgcolor: 'background.paper', mt: 1 }}
          component="nav"
          aria-label="mailbox folders"
        >
          <List>
            <ListItemLink to="/inbox" open={open} onClick={handleClick} />
            <Collapse component="li" in={open} timeout="auto" unmountOnExit>
              <List disablePadding>
                <ListItemLink sx={{ pl: 4 }} to="/inbox/important" />
              </List>
            </Collapse>
            <ListItemLink to="/trash" />
            <ListItemLink to="/spam" />
          </List>
        </Box>
      </Box>
    </MemoryRouter>
  );
}

접근성 (Accessibility)

(WAI-ARIA: https://www.w3.org/WAI/ARIA/apg/patterns/breadcrumb/)

Breadcrumbs 컴포넌트에 aria-label 설명을 추가하는 것을 잊지 마세요.

이 컴포넌트의 접근성은 다음에 의존합니다.

  • 링크 집합이 순서 있는 목록(<ol> 요소)으로 구성됩니다.
  • 스크린 리더가 링크 사이의 시각적 구분자를 읽지 않도록 aria-hidden으로 숨깁니다.
  • aria-label로 라벨이 지정된 nav 요소가 구조를 브레드크럼 트레일로 식별하고, 탐색 landmark가 되어 쉽게 찾을 수 있게 합니다.

데모 (Demos)

이 React 컴포넌트 사용에 대한 예시와 세부 사항은 컴포넌트 데모 페이지를 참고하세요.

Import

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

Props

Name Type Default Required Description
children node - No
classes object - No 컴포넌트에 적용되는 스타일을 오버라이드하거나 확장합니다.
component elementType - No
expandText string 'Show path' No
itemsAfterCollapse integer 1 No
itemsBeforeCollapse integer 1 No
maxItems integer 8 No
separator node '/' No
slotProps { collapsedIcon?: func | object } {} No
slots { CollapsedIcon?: elementType } {} No
sx Array<func | object | bool> | func | object - No 시스템 오버라이드와 추가 CSS 스타일을 정의할 수 있게 해주는 system prop입니다.

참고: ref는 루트 요소(HTMLElement)로 전달됩니다.

다른 추가 props는 루트 요소(Typography)로 제공됩니다.

상속 (Inheritance)

위에 명시적으로 문서화되지는 않았지만, Typography 컴포넌트의 props도 Breadcrumbs에서 사용할 수 있습니다.

테마 기본 props (Theme default props)

MuiBreadcrumbs를 사용해 테마로 이 컴포넌트의 기본 props를 변경할 수 있습니다.

CSS

규칙 이름 (Rule name)

Global class Rule name Description
- li li 요소에 적용되는 스타일입니다.
- ol ol 요소에 적용되는 스타일입니다.
- root 루트 요소에 적용되는 스타일입니다.
- separator 구분자 요소에 적용되는 스타일입니다.

소스 코드 (Source code)

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

데모 (Demos)

이 React 컴포넌트 사용에 대한 예시와 세부 사항은 컴포넌트 데모 페이지를 참고하세요.

Import

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

Props

Name Type Default Required Description
children node - No
classes object - No 컴포넌트에 적용되는 스타일을 오버라이드하거나 확장합니다.
color 'primary' | 'secondary' | 'success' | 'error' | 'info' | 'warning' | 'textPrimary' | 'textSecondary' | 'textDisabled' | string 'primary' No
component element type - No
sx Array<func | object | bool> | func | object - No 시스템 오버라이드와 추가 CSS 스타일을 정의할 수 있게 해주는 system prop입니다.
TypographyClasses object - No
underline 'always' | 'hover' | 'none' 'always' No
variant 'body1' | 'body2' | 'button' | 'caption' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'inherit' | 'overline' | 'subtitle1' | 'subtitle2' | string 'inherit' No

참고: ref는 루트 요소(HTMLAnchorElement)로 전달됩니다.

다른 추가 props는 루트 요소(Typography)로 제공됩니다.

상속 (Inheritance)

위에 명시적으로 문서화되지는 않았지만, Typography 컴포넌트의 props도 Link에서 사용할 수 있습니다.

테마 기본 props (Theme default props)

MuiLink를 사용해 테마로 이 컴포넌트의 기본 props를 변경할 수 있습니다.

CSS

규칙 이름 (Rule name)

Global class Rule name Description
- button component="button"일 때 루트 요소에 적용되는 스타일입니다.
.Mui-focusVisible - 링크가 키보드 포커스 상태일 때 루트 요소에 적용되는 상태 클래스입니다.
- root 루트 요소에 적용되는 스타일입니다.
- underlineAlways underline="always"일 때 루트 요소에 적용되는 스타일입니다.
- underlineHover underline="hover"일 때 루트 요소에 적용되는 스타일입니다.
- underlineNone underline="none"일 때 루트 요소에 적용되는 스타일입니다.

소스 코드 (Source code)

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

Typography API

데모 (Demos)

이 React 컴포넌트 사용에 대한 예시와 세부 사항은 컴포넌트 데모 페이지를 참고하세요.

Import

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

Props

Name Type Default Required Description
align 'center' | 'inherit' | 'justify' | 'left' | 'right' 'inherit' No
children node - No
classes object - No 컴포넌트에 적용되는 스타일을 오버라이드하거나 확장합니다.
color 'primary' | 'secondary' | 'success' | 'error' | 'info' | 'warning' | 'textPrimary' | 'textSecondary' | 'textDisabled' | string - No
component elementType - No
gutterBottom bool false No
noWrap bool false No
sx Array<func | object | bool> | func | object - No 시스템 오버라이드와 추가 CSS 스타일을 정의할 수 있게 해주는 system prop입니다.
variant 'body1' | 'body2' | 'button' | 'caption' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'inherit' | 'overline' | 'subtitle1' | 'subtitle2' | string 'body1' No
variantMapping object `{
h1: 'h1',
h2: 'h2',
h3: 'h3',
h4: 'h4',
h5: 'h5',
h6: 'h6',
subtitle1: 'h6',
subtitle2: 'h6',
body1: 'p',
body2: 'p',
inherit: 'p',
}` No

참고: ref는 루트 요소(HTMLParagraphElement)로 전달됩니다.

다른 추가 props는 루트 요소(네이티브 요소)로 제공됩니다.

테마 기본 props (Theme default props)

MuiTypography를 사용해 테마로 이 컴포넌트의 기본 props를 변경할 수 있습니다.

CSS

규칙 이름 (Rule name)

Global class Rule name Description
- alignCenter align="center"일 때 루트 요소에 적용되는 스타일입니다.
- alignJustify align="justify"일 때 루트 요소에 적용되는 스타일입니다.
- alignLeft align="left"일 때 루트 요소에 적용되는 스타일입니다.
- alignRight align="right"일 때 루트 요소에 적용되는 스타일입니다.
- body1 variant="body1"일 때 루트 요소에 적용되는 스타일입니다.
- body2 variant="body2"일 때 루트 요소에 적용되는 스타일입니다.
- button variant="button"일 때 루트 요소에 적용되는 스타일입니다.
- caption variant="caption"일 때 루트 요소에 적용되는 스타일입니다.
- gutterBottom gutterBottom={true}일 때 루트 요소에 적용되는 스타일입니다.
- h1 variant="h1"일 때 루트 요소에 적용되는 스타일입니다.
- h2 variant="h2"일 때 루트 요소에 적용되는 스타일입니다.
- h3 variant="h3"일 때 루트 요소에 적용되는 스타일입니다.
- h4 variant="h4"일 때 루트 요소에 적용되는 스타일입니다.
- h5 variant="h5"일 때 루트 요소에 적용되는 스타일입니다.
- h6 variant="h6"일 때 루트 요소에 적용되는 스타일입니다.
- inherit variant="inherit"일 때 루트 요소에 적용되는 스타일입니다.
- noWrap nowrap={true}일 때 루트 요소에 적용되는 스타일입니다.
- overline variant="overline"일 때 루트 요소에 적용되는 스타일입니다.
- root 루트 요소에 적용되는 스타일입니다.
- subtitle1 variant="subtitle1"일 때 루트 요소에 적용되는 스타일입니다.
- subtitle2 variant="subtitle2"일 때 루트 요소에 적용되는 스타일입니다.

소스 코드 (Source code)

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

더 알아보기 (Learn more)

  • Material UI 내비게이션 컴포넌트 둘러보기