Lists

Lists (리스트)

Lists는 텍스트나 이미지의 연속적인 세로 인덱스예요.

Lists는 텍스트 또는 이미지의 연속적인 그룹이에요. 아이콘과 텍스트로 표현되는 기본 동작과 보조 동작을 포함하는 항목들로 구성돼요.

출처: 문서

본문

Introduction (소개)

Lists는 텍스트나 이미지의 연속적인 세로 인덱스를 통해 정보를 간결하고 따라가기 쉬운 형식으로 제시해요.

Material UI Lists는 관련된 컴포넌트 모음으로 구현돼요:

  • List: 리스트 항목을 위한 래퍼. 기본적으로 <ul>로 렌더링돼요.
  • List Item: 일반적인 리스트 항목. 기본적으로 <li>로 렌더링돼요.
  • List Item Button: 리스트 항목 안에서 사용되는 액션 요소.
  • List Item Icon: 리스트 항목 안에서 사용되는 아이콘.
  • List Item Avatar: 리스트 항목 안에서 사용되는 아바타.
  • List Item Text: 리스트 항목 안에서 텍스트 콘텐츠를 표시하는 데 사용되는 컨테이너.
  • List Divider: 리스트 항목 사이의 구분선.
  • List Subheader: 중첩 리스트를 위한 라벨.
import Box from '@mui/material/Box';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import Divider from '@mui/material/Divider';
import InboxIcon from '@mui/icons-material/Inbox';
import DraftsIcon from '@mui/icons-material/Drafts';

export default function BasicList() {
  return (
    <Box sx={{ width: '100%', maxWidth: 360, bgcolor: 'background.paper' }}>
      <nav aria-label="main mailbox folders">
        <List>
          <ListItem disablePadding>
            <ListItemButton>
              <ListItemIcon>
                <InboxIcon />
              </ListItemIcon>
              <ListItemText primary="Inbox" />
            </ListItemButton>
          </ListItem>
          <ListItem disablePadding>
            <ListItemButton>
              <ListItemIcon>
                <DraftsIcon />
              </ListItemIcon>
              <ListItemText primary="Drafts" />
            </ListItemButton>
          </ListItem>
        </List>
      </nav>
      <Divider />
      <nav aria-label="secondary mailbox folders">
        <List>
          <ListItem disablePadding>
            <ListItemButton>
              <ListItemText primary="Trash" />
            </ListItemButton>
          </ListItem>
          <ListItem disablePadding>
            <ListItemButton component="a" href="#simple-list">
              <ListItemText primary="Spam" />
            </ListItemButton>
          </ListItem>
        </List>
      </nav>
    </Box>
  );
}

이전 데모의 마지막 항목은 링크를 렌더링하는 방법을 보여줘요:

<ListItemButton component="a" href="#simple-list">
  <ListItemText primary="Spam" />
</ListItemButton>

문서의 이 섹션 다음에서 React Router를 사용한 데모를 찾을 수 있어요.

Basics (기본)

import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';

Nested List (중첩 리스트)

import * as React from 'react';
import ListSubheader from '@mui/material/ListSubheader';
import List from '@mui/material/List';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import Collapse from '@mui/material/Collapse';
import InboxIcon from '@mui/icons-material/MoveToInbox';
import DraftsIcon from '@mui/icons-material/Drafts';
import SendIcon from '@mui/icons-material/Send';
import ExpandLess from '@mui/icons-material/ExpandLess';
import ExpandMore from '@mui/icons-material/ExpandMore';
import StarBorder from '@mui/icons-material/StarBorder';

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

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

  return (
    <List
      sx={{ width: '100%', maxWidth: 360, bgcolor: 'background.paper' }}
      component="nav"
      aria-labelledby="nested-list-subheader"
      subheader={
        <ListSubheader component="div" id="nested-list-subheader">
          Nested List Items
        </ListSubheader>
      }
    >
      <ListItemButton>
        <ListItemIcon>
          <SendIcon />
        </ListItemIcon>
        <ListItemText primary="Sent mail" />
      </ListItemButton>
      <ListItemButton>
        <ListItemIcon>
          <DraftsIcon />
        </ListItemIcon>
        <ListItemText primary="Drafts" />
      </ListItemButton>
      <ListItemButton onClick={handleClick}>
        <ListItemIcon>
          <InboxIcon />
        </ListItemIcon>
        <ListItemText primary="Inbox" />
        {open ? <ExpandLess /> : <ExpandMore />}
      </ListItemButton>
      <Collapse in={open} timeout="auto" unmountOnExit>
        <List component="div" disablePadding>
          <ListItemButton sx={{ pl: 4 }}>
            <ListItemIcon>
              <StarBorder />
            </ListItemIcon>
            <ListItemText primary="Starred" />
          </ListItemButton>
        </List>
      </Collapse>
    </List>
  );
}

Folder List (폴더 리스트)

import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemText from '@mui/material/ListItemText';
import ListItemAvatar from '@mui/material/ListItemAvatar';
import Avatar from '@mui/material/Avatar';
import ImageIcon from '@mui/icons-material/Image';
import WorkIcon from '@mui/icons-material/Work';
import BeachAccessIcon from '@mui/icons-material/BeachAccess';

export default function FolderList() {
  return (
    <List sx={{ width: '100%', maxWidth: 360, bgcolor: 'background.paper' }}>
      <ListItem>
        <ListItemAvatar>
          <Avatar>
            <ImageIcon />
          </Avatar>
        </ListItemAvatar>
        <ListItemText primary="Photos" secondary="Jan 9, 2014" />
      </ListItem>
      <ListItem>
        <ListItemAvatar>
          <Avatar>
            <WorkIcon />
          </Avatar>
        </ListItemAvatar>
        <ListItemText primary="Work" secondary="Jan 7, 2014" />
      </ListItem>
      <ListItem>
        <ListItemAvatar>
          <Avatar>
            <BeachAccessIcon />
          </Avatar>
        </ListItemAvatar>
        <ListItemText primary="Vacation" secondary="July 20, 2014" />
      </ListItem>
    </List>
  );
}

Interactive (대화형)

아래는 다양한 설정의 시각적 결과를 살펴볼 수 있는 대화형 데모예요:

import * as React from 'react';
import { styled } from '@mui/material/styles';
import Box from '@mui/material/Box';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemAvatar from '@mui/material/ListItemAvatar';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import Avatar from '@mui/material/Avatar';
import IconButton from '@mui/material/IconButton';
import FormGroup from '@mui/material/FormGroup';
import FormControlLabel from '@mui/material/FormControlLabel';
import Checkbox from '@mui/material/Checkbox';
import Grid from '@mui/material/Grid';
import Typography from '@mui/material/Typography';
import FolderIcon from '@mui/icons-material/Folder';
import DeleteIcon from '@mui/icons-material/Delete';

function generate(element: React.ReactElement<unknown>) {
  return [0, 1, 2].map((value) =>
    React.cloneElement(element, {
      key: value,
    }),
  );
}

const Demo = styled('div')(({ theme }) => ({
  backgroundColor: (theme.vars || theme).palette.background.paper,
}));

export default function InteractiveList() {
  const [dense, setDense] = React.useState(false);
  const [secondary, setSecondary] = React.useState(false);

  return (
    <Box sx={{ flexGrow: 1, maxWidth: 752 }}>
      <FormGroup row>
        <FormControlLabel
          control={
            <Checkbox
              checked={dense}
              onChange={(event) => setDense(event.target.checked)}
            />
          }
          label="Enable dense"
        />
        <FormControlLabel
          control={
            <Checkbox
              checked={secondary}
              onChange={(event) => setSecondary(event.target.checked)}
            />
          }
          label="Enable secondary text"
        />
      </FormGroup>
      <Grid container spacing={2}>
        <Grid
          size={{
            xs: 12,
            md: 6,
          }}
        >
          <Typography sx={{ mt: 4, mb: 2 }} variant="h6" component="div">
            Text only
          </Typography>
          <Demo>
            <List dense={dense}>
              {generate(
                <ListItem>
                  <ListItemText
                    primary="Single-line item"
                    secondary={secondary ? 'Secondary text' : null}
                  />
                </ListItem>,
              )}
            </List>
          </Demo>
        </Grid>
        <Grid
          size={{
            xs: 12,
            md: 6,
          }}
        >
          <Typography sx={{ mt: 4, mb: 2 }} variant="h6" component="div">
            Icon with text
          </Typography>
          <Demo>
            <List dense={dense}>
              {generate(
                <ListItem>
                  <ListItemIcon>
                    <FolderIcon />
                  </ListItemIcon>
                  <ListItemText
                    primary="Single-line item"
                    secondary={secondary ? 'Secondary text' : null}
                  />
                </ListItem>,
              )}
            </List>
          </Demo>
        </Grid>
      </Grid>
      <Grid container spacing={2}>
        <Grid
          size={{
            xs: 12,
            md: 6,
          }}
        >
          <Typography sx={{ mt: 4, mb: 2 }} variant="h6" component="div">
            Avatar with text
          </Typography>
          <Demo>
            <List dense={dense}>
              {generate(
                <ListItem>
                  <ListItemAvatar>
                    <Avatar>
                      <FolderIcon />
                    </Avatar>
                  </ListItemAvatar>
                  <ListItemText
                    primary="Single-line item"
                    secondary={secondary ? 'Secondary text' : null}
                  />
                </ListItem>,
              )}
            </List>
          </Demo>
        </Grid>
        <Grid
          size={{
            xs: 12,
            md: 6,
          }}
        >
          <Typography sx={{ mt: 4, mb: 2 }} variant="h6" component="div">
            Avatar with text and icon
          </Typography>
          <Demo>
            <List dense={dense}>
              {generate(
                <ListItem
                  secondaryAction={
                    <IconButton edge="end" aria-label="delete">
                      <DeleteIcon />
                    </IconButton>
                  }
                >
                  <ListItemAvatar>
                    <Avatar>
                      <FolderIcon />
                    </Avatar>
                  </ListItemAvatar>
                  <ListItemText
                    primary="Single-line item"
                    secondary={secondary ? 'Secondary text' : null}
                  />
                </ListItem>,
              )}
            </List>
          </Demo>
        </Grid>
      </Grid>
    </Box>
  );
}

Selected ListItem (선택된 ListItem)

import * as React from 'react';
import Box from '@mui/material/Box';
import List from '@mui/material/List';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import Divider from '@mui/material/Divider';
import InboxIcon from '@mui/icons-material/Inbox';
import DraftsIcon from '@mui/icons-material/Drafts';

export default function SelectedListItem() {
  const [selectedIndex, setSelectedIndex] = React.useState(1);

  const handleListItemClick = (
    event: React.MouseEvent<HTMLDivElement, MouseEvent>,
    index: number,
  ) => {
    setSelectedIndex(index);
  };

  return (
    <Box sx={{ width: '100%', maxWidth: 360, bgcolor: 'background.paper' }}>
      <List component="nav" aria-label="main mailbox folders">
        <ListItemButton
          selected={selectedIndex === 0}
          onClick={(event) => handleListItemClick(event, 0)}
        >
          <ListItemIcon>
            <InboxIcon />
          </ListItemIcon>
          <ListItemText primary="Inbox" />
        </ListItemButton>
        <ListItemButton
          selected={selectedIndex === 1}
          onClick={(event) => handleListItemClick(event, 1)}
        >
          <ListItemIcon>
            <DraftsIcon />
          </ListItemIcon>
          <ListItemText primary="Drafts" />
        </ListItemButton>
      </List>
      <Divider />
      <List component="nav" aria-label="secondary mailbox folder">
        <ListItemButton
          selected={selectedIndex === 2}
          onClick={(event) => handleListItemClick(event, 2)}
        >
          <ListItemText primary="Trash" />
        </ListItemButton>
        <ListItemButton
          selected={selectedIndex === 3}
          onClick={(event) => handleListItemClick(event, 3)}
        >
          <ListItemText primary="Spam" />
        </ListItemButton>
      </List>
    </Box>
  );
}

Align list items (리스트 항목 정렬)

세 줄 이상을 표시할 때 아바타가 맨 위에 정렬되지 않아요. Material Design 지침에 따라 alignItems="flex-start" prop을 설정해서 아바타를 맨 위에 정렬해야 해요:

import * as React from 'react';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import Divider from '@mui/material/Divider';
import ListItemText from '@mui/material/ListItemText';
import ListItemAvatar from '@mui/material/ListItemAvatar';
import Avatar from '@mui/material/Avatar';
import Typography from '@mui/material/Typography';

export default function AlignItemsList() {
  return (
    <List sx={{ width: '100%', maxWidth: 360, bgcolor: 'background.paper' }}>
      <ListItem alignItems="flex-start">
        <ListItemAvatar>
          <Avatar alt="Remy Sharp" src="/static/images/avatar/1.jpg" />
        </ListItemAvatar>
        <ListItemText
          primary="Brunch this weekend?"
          secondary={
            <React.Fragment>
              <Typography
                component="span"
                variant="body2"
                sx={{ color: 'text.primary', display: 'inline' }}
              >
                Ali Connors
              </Typography>
              {" — I'll be in your neighborhood doing errands this…"}
            </React.Fragment>
          }
        />
      </ListItem>
      <Divider variant="inset" component="li" />
      <ListItem alignItems="flex-start">
        <ListItemAvatar>
          <Avatar alt="Travis Howard" src="/static/images/avatar/2.jpg" />
        </ListItemAvatar>
        <ListItemText
          primary="Summer BBQ"
          secondary={
            <React.Fragment>
              <Typography
                component="span"
                variant="body2"
                sx={{ color: 'text.primary', display: 'inline' }}
              >
                to Scott, Alex, Jennifer
              </Typography>
              {" — Wish I could come, but I'm out of town this…"}
            </React.Fragment>
          }
        />
      </ListItem>
      <Divider variant="inset" component="li" />
      <ListItem alignItems="flex-start">
        <ListItemAvatar>
          <Avatar alt="Cindy Baker" src="/static/images/avatar/3.jpg" />
        </ListItemAvatar>
        <ListItemText
          primary="Oui Oui"
          secondary={
            <React.Fragment>
              <Typography
                component="span"
                variant="body2"
                sx={{ color: 'text.primary', display: 'inline' }}
              >
                Sandra Adams
              </Typography>
              {' — Do you have Paris recommendations? Have you ever…'}
            </React.Fragment>
          }
        />
      </ListItem>
    </List>
  );
}

List Controls (리스트 컨트롤)

Checkbox

체크박스는 기본 액션(primary action)이 될 수도 있고 보조 액션(secondary action)이 될 수도 있어요.

체크박스는 리스트 항목의 기본 액션이자 상태 표시기예요. 댓글 버튼은 보조 액션이자 별도의 대상이에요.

import * as React from 'react';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import Checkbox from '@mui/material/Checkbox';
import IconButton from '@mui/material/IconButton';
import CommentIcon from '@mui/icons-material/Comment';

export default function CheckboxList() {
  const [checked, setChecked] = React.useState([0]);

  const handleToggle = (value: number) => () => {
    const currentIndex = checked.indexOf(value);
    const newChecked = [...checked];

    if (currentIndex === -1) {
      newChecked.push(value);
    } else {
      newChecked.splice(currentIndex, 1);
    }

    setChecked(newChecked);
  };

  return (
    <List sx={{ width: '100%', maxWidth: 360, bgcolor: 'background.paper' }}>
      {[0, 1, 2, 3].map((value) => {
        const labelId = `checkbox-list-label-${value}`;

        return (
          <ListItem
            key={value}
            secondaryAction={
              <IconButton edge="end" aria-label="comments">
                <CommentIcon />
              </IconButton>
            }
            disablePadding
          >
            <ListItemButton role={undefined} onClick={handleToggle(value)} dense>
              <ListItemIcon>
                <Checkbox
                  edge="start"
                  checked={checked.includes(value)}
                  tabIndex={-1}
                  disableRipple
                  slotProps={{ input: { 'aria-labelledby': labelId } }}
                />
              </ListItemIcon>
              <ListItemText id={labelId} primary={`Line item ${value + 1}`} />
            </ListItemButton>
          </ListItem>
        );
      })}
    </List>
  );
}

체크박스는 리스트 항목의 보조 액션이자 별도의 대상이에요.

import * as React from 'react';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemText from '@mui/material/ListItemText';
import ListItemAvatar from '@mui/material/ListItemAvatar';
import Checkbox from '@mui/material/Checkbox';
import Avatar from '@mui/material/Avatar';

export default function CheckboxListSecondary() {
  const [checked, setChecked] = React.useState([1]);

  const handleToggle = (value: number) => () => {
    const currentIndex = checked.indexOf(value);
    const newChecked = [...checked];

    if (currentIndex === -1) {
      newChecked.push(value);
    } else {
      newChecked.splice(currentIndex, 1);
    }

    setChecked(newChecked);
  };

  return (
    <List dense sx={{ width: '100%', maxWidth: 360, bgcolor: 'background.paper' }}>
      {[0, 1, 2, 3].map((value) => {
        const labelId = `checkbox-list-secondary-label-${value}`;
        return (
          <ListItem
            key={value}
            secondaryAction={
              <Checkbox
                edge="end"
                onChange={handleToggle(value)}
                checked={checked.includes(value)}
                slotProps={{ input: { 'aria-labelledby': labelId } }}
              />
            }
            disablePadding
          >
            <ListItemButton>
              <ListItemAvatar>
                <Avatar
                  alt={`Avatar n°${value + 1}`}
                  src={`/static/images/avatar/${value + 1}.jpg`}
                />
              </ListItemAvatar>
              <ListItemText id={labelId} primary={`Line item ${value + 1}`} />
            </ListItemButton>
          </ListItem>
        );
      })}
    </List>
  );
}

Switch

스위치는 보조 액션이자 별도의 대상이에요.

import * as React from 'react';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import ListSubheader from '@mui/material/ListSubheader';
import Switch from '@mui/material/Switch';
import WifiIcon from '@mui/icons-material/Wifi';
import BluetoothIcon from '@mui/icons-material/Bluetooth';

export default function SwitchListSecondary() {
  const [checked, setChecked] = React.useState(['wifi']);

  const handleToggle = (value: string) => () => {
    const currentIndex = checked.indexOf(value);
    const newChecked = [...checked];

    if (currentIndex === -1) {
      newChecked.push(value);
    } else {
      newChecked.splice(currentIndex, 1);
    }

    setChecked(newChecked);
  };

  return (
    <List
      sx={{ width: '100%', maxWidth: 360, bgcolor: 'background.paper' }}
      subheader={<ListSubheader>Settings</ListSubheader>}
    >
      <ListItem>
        <ListItemIcon>
          <WifiIcon />
        </ListItemIcon>
        <ListItemText id="switch-list-label-wifi" primary="Wi-Fi" />
        <Switch
          edge="end"
          onChange={handleToggle('wifi')}
          checked={checked.includes('wifi')}
          slotProps={{
            input: { 'aria-labelledby': 'switch-list-label-wifi' },
          }}
        />
      </ListItem>
      <ListItem>
        <ListItemIcon>
          <BluetoothIcon />
        </ListItemIcon>
        <ListItemText id="switch-list-label-bluetooth" primary="Bluetooth" />
        <Switch
          edge="end"
          onChange={handleToggle('bluetooth')}
          checked={checked.includes('bluetooth')}
          slotProps={{
            input: { 'aria-labelledby': 'switch-list-label-bluetooth' },
          }}
        />
      </ListItem>
    </List>
  );
}

Sticky subheader (고정 서브헤더)

스크롤할 때 서브헤더는 다음 서브헤더에 의해 화면 밖으로 밀려날 때까지 화면 상단에 고정된 상태를 유지해요. 이 기능은 CSS sticky positioning에 의존해요.

import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemText from '@mui/material/ListItemText';
import ListSubheader from '@mui/material/ListSubheader';

export default function PinnedSubheaderList() {
  return (
    <List
      sx={{
        width: '100%',
        maxWidth: 360,
        bgcolor: 'background.paper',
        position: 'relative',
        overflow: 'auto',
        maxHeight: 300,
        '& ul': { padding: 0 },
      }}
      subheader={<li />}
    >
      {[0, 1, 2, 3, 4].map((sectionId) => (
        <li key={`section-${sectionId}`}>
          <ul>
            <ListSubheader>{`I'm sticky ${sectionId}`}</ListSubheader>
            {[0, 1, 2].map((item) => (
              <ListItem key={`item-${sectionId}-${item}`}>
                <ListItemText primary={`Item ${item}`} />
              </ListItem>
            ))}
          </ul>
        </li>
      ))}
    </List>
  );
}

Inset List Item (인셋 리스트 항목)

inset prop은 앞에 아이콘이나 아바타가 없는 리스트 항목이 아이콘이나 아바타가 있는 항목과 올바르게 정렬되도록 해줘요.

import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import StarIcon from '@mui/icons-material/Star';

export default function InsetList() {
  return (
    <List
      sx={{ width: '100%', maxWidth: 360, bgcolor: 'background.paper' }}
      aria-label="contacts"
    >
      <ListItem disablePadding>
        <ListItemButton>
          <ListItemIcon>
            <StarIcon />
          </ListItemIcon>
          <ListItemText primary="Chelsea Otakan" />
        </ListItemButton>
      </ListItem>
      <ListItem disablePadding>
        <ListItemButton>
          <ListItemText inset primary="Eric Hoffman" />
        </ListItemButton>
      </ListItem>
    </List>
  );
}

Gutterless list (거터 없는 리스트)

자체 거터(gutters)를 정의하는 컴포넌트 안에서 리스트를 렌더링할 때, ListItem 거터를 disableGutters로 비활성화할 수 있어요.

import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemText from '@mui/material/ListItemText';
import CommentIcon from '@mui/icons-material/Comment';
import IconButton from '@mui/material/IconButton';

export default function GutterlessList() {
  return (
    <List sx={{ width: '100%', maxWidth: 360, bgcolor: 'background.paper' }}>
      {[1, 2, 3].map((value) => (
        <ListItem
          key={value}
          disableGutters
          secondaryAction={
            <IconButton aria-label="comment">
              <CommentIcon />
            </IconButton>
          }
        >
          <ListItemText primary={`Line item ${value}`} />
        </ListItem>
      ))}
    </List>
  );
}

Virtualized List (가상화 리스트)

다음 예제에서는 List 컴포넌트와 함께 react-window를 사용하는 방법을 보여줘요. 200개의 행을 렌더링하며 더 많은 것도 쉽게 처리할 수 있어요. 가상화는 성능 문제를 해결하는 데 도움이 돼요.

import Box from '@mui/material/Box';
import ListItem from '@mui/material/ListItem';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemText from '@mui/material/ListItemText';
import { List, RowComponentProps } from 'react-window';

function renderRow(props: RowComponentProps) {
  const { index, style } = props;

  return (
    <ListItem style={style} key={index} component="div" disablePadding>
      <ListItemButton>
        <ListItemText primary={`Item ${index + 1}`} />
      </ListItemButton>
    </ListItem>
  );
}

export default function VirtualizedList() {
  return (
    <Box
      sx={{ width: '100%', height: 400, maxWidth: 360, bgcolor: 'background.paper' }}
    >
      <List
        rowHeight={46}
        rowCount={200}
        style={{
          height: 400,
          width: 360,
        }}
        rowProps={{}}
        overscanCount={5}
        rowComponent={renderRow}
      />
    </Box>
  );
}

가능할 때 react-window를 사용하는 것을 권장해요. 이 라이브러리가 사용 사례를 다루지 못한다면 react-virtuoso 같은 대안을 고려해보세요.

Customization (커스터마이징)

여기 컴포넌트를 커스터마이즈하는 몇 가지 예제가 있어요. 이에 대해 더 자세히 알고 싶다면 오버라이드 문서 페이지에서 배울 수 있어요.

import * as React from 'react';
import Box from '@mui/material/Box';
import { styled, ThemeProvider, createTheme } from '@mui/material/styles';
import Divider from '@mui/material/Divider';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import Paper from '@mui/material/Paper';
import IconButton from '@mui/material/IconButton';
import Tooltip from '@mui/material/Tooltip';
import ArrowRight from '@mui/icons-material/ArrowRight';
import KeyboardArrowDown from '@mui/icons-material/KeyboardArrowDown';
import Home from '@mui/icons-material/Home';
import Settings from '@mui/icons-material/Settings';
import People from '@mui/icons-material/People';
import PermMedia from '@mui/icons-material/PermMedia';
import Dns from '@mui/icons-material/Dns';
import Public from '@mui/icons-material/Public';

const data = [
  { icon: <People />, label: 'Authentication' },
  { icon: <Dns />, label: 'Database' },
  { icon: <PermMedia />, label: 'Storage' },
  { icon: <Public />, label: 'Hosting' },
];

const FireNav = styled(List)<{ component?: React.ElementType }>({
  '& .MuiListItemButton-root': {
    paddingLeft: 24,
    paddingRight: 24,
  },
  '& .MuiListItemIcon-root': {
    minWidth: 0,
    marginRight: 16,
  },
  '& .MuiSvgIcon-root': {
    fontSize: 20,
  },
});

export default function CustomizedList() {
  const [open, setOpen] = React.useState(true);
  return (
    <Box sx={{ display: 'flex' }}>
      <ThemeProvider
        theme={createTheme({
          components: {
            MuiListItemButton: {
              defaultProps: {
                disableTouchRipple: true,
              },
            },
          },
          palette: {
            mode: 'dark',
            primary: { main: 'rgb(102, 157, 246)' },
            background: { paper: 'rgb(5, 30, 52)' },
          },
        })}
      >
        <Paper elevation={0} sx={{ maxWidth: 256 }}>
          <FireNav component="nav" disablePadding>
            <ListItemButton component="a" href="#customized-list">
              <ListItemIcon sx={{ fontSize: 20 }}>🔥</ListItemIcon>
              <ListItemText
                sx={{ my: 0 }}
                primary="Firebash"
                slotProps={{
                  primary: {
                    sx: { fontSize: 20, fontWeight: 'medium', letterSpacing: 0 },
                  },
                }}
              />
            </ListItemButton>
            <Divider />
            <ListItem component="div" disablePadding>
              <ListItemButton sx={{ height: 56 }}>
                <ListItemIcon>
                  <Home color="primary" />
                </ListItemIcon>
                <ListItemText
                  primary="Project Overview"
                  slotProps={{
                    primary: {
                      color: 'primary',
                      sx: { fontWeight: 'medium' },
                      variant: 'body2',
                    },
                  }}
                />
              </ListItemButton>
              <Tooltip title="Project Settings">
                <IconButton
                  size="large"
                  sx={{
                    '& svg': {
                      color: 'rgba(255,255,255,0.8)',
                      transition: '0.2s',
                      transform: 'translateX(0) rotate(0)',
                    },
                    '&:hover, &:focus': {
                      bgcolor: 'unset',
                      '& svg:first-of-type': {
                        transform: 'translateX(-4px) rotate(-20deg)',
                      },
                      '& svg:last-of-type': {
                        right: 0,
                        opacity: 1,
                      },
                    },
                    '&::after': {
                      content: '""',
                      position: 'absolute',
                      height: '80%',
                      display: 'block',
                      left: 0,
                      width: '1px',
                      bgcolor: 'divider',
                    },
                  }}
                >
                  <Settings />
                  <ArrowRight sx={{ position: 'absolute', right: 4, opacity: 0 }} />
                </IconButton>
              </Tooltip>
            </ListItem>
            <Divider />
            <Box
              sx={[
                open
                  ? {
                      bgcolor: 'rgba(71, 98, 130, 0.2)',
                    }
                  : {
                      bgcolor: null,
                    },
                open
                  ? {
                      pb: 2,
                    }
                  : {
                      pb: 0,
                    },
              ]}
            >
              <ListItemButton
                alignItems="flex-start"
                onClick={() => setOpen(!open)}
                sx={[
                  {
                    px: 3,
                    pt: 2.5,
                  },
                  open
                    ? {
                        pb: 0,
                      }
                    : {
                        pb: 2.5,
                      },
                  open
                    ? {
                        '&:hover, &:focus': {
                          '& svg': {
                            opacity: 1,
                          },
                        },
                      }
                    : {
                        '&:hover, &:focus': {
                          '& svg': {
                            opacity: 0,
                          },
                        },
                      },
                ]}
              >
                <ListItemText
                  primary="Build"
                  secondary="Authentication, Firestore Database, Realtime Database, Storage, Hosting, Functions, and Machine Learning"
                  slotProps={{
                    primary: {
                      sx: {
                        fontSize: 15,
                        fontWeight: 'medium',
                        lineHeight: '20px',
                        mb: '2px',
                      },
                    },
                    secondary: {
                      noWrap: true,
                      sx: {
                        fontSize: 12,
                        lineHeight: '16px',
                        color: open ? 'rgba(0,0,0,0)' : 'rgba(255,255,255,0.5)',
                      },
                    },
                  }}
                  sx={{ my: 0 }}
                />
                <KeyboardArrowDown
                  sx={[
                    {
                      mr: -1,
                      opacity: 0,
                      transition: '0.2s',
                    },
                    open
                      ? {
                          transform: 'rotate(-180deg)',
                        }
                      : {
                          transform: 'rotate(0)',
                        },
                  ]}
                />
              </ListItemButton>
              {open &&
                data.map((item) => (
                  <ListItemButton
                    key={item.label}
                    sx={{ py: 0, minHeight: 32, color: 'rgba(255,255,255,.8)' }}
                  >
                    <ListItemIcon sx={{ color: 'inherit' }}>
                      {item.icon}
                    </ListItemIcon>
                    <ListItemText
                      primary={item.label}
                      slotProps={{
                        primary: { sx: { fontSize: 14, fontWeight: 'medium' } },
                      }}
                    />
                  </ListItemButton>
                ))}
            </Box>
          </FireNav>
        </Paper>
      </ThemeProvider>
    </Box>
  );
}

Collapse API (Collapse API)

Demos (데모)

이 React 컴포넌트 사용에 대한 예제와 자세한 내용은 컴포넌트 데모 페이지를 방문해보세요:

Import (불러오기)

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

Props (속성)

Name Type Default Required Description
addEndListener function(node: HTMLElement, done: Function) => void - No
children node - No
classes object - No Override or extend the styles applied to the component.
collapsedSize number | string '0px' No
component element type - No
disablePrefersReducedMotion bool false No
easing { enter?: string, exit?: string } | string - No
in bool - No
orientation 'horizontal' | 'vertical' 'vertical' No
slotProps { root?: func | object, wrapper?: func | object, wrapperInner?: func | object } {} No
slots { root?: elementType, wrapper?: elementType, wrapperInner?: elementType } {} No
sx Array<func | object | bool> | func | object - No The system prop that allows defining system overrides as well as additional CSS styles.
timeout 'auto' | number | { appear?: number, enter?: number, exit?: number } duration.standard No

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

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

Inheritance (상속)

위에 명시적으로 문서화되지는 않았지만, Transition 컴포넌트의 props도 Collapse에서 사용할 수 있어요. 일부 컴포넌트는 react-transition-group을 기본 지원해요.

Theme default props (테마 기본 props)

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

Slots (슬롯)

Name Default Class Description
root 'div' .MuiCollapse-root The component that renders the root.
wrapper 'div' .MuiCollapse-wrapper The component that renders the wrapper.
wrapperInner 'div' .MuiCollapse-wrapperInner The component that renders the inner wrapper.

CSS

Rule name (규칙 이름)

Global class Rule name Description
- entered Styles applied to the root element when the transition has entered.
- hidden Styles applied to the root element when the transition has exited and collapsedSize = 0px.
- horizontal State class applied to the root element if orientation="horizontal".

Source code (소스 코드)

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

Divider API (Divider API)

Demos (데모)

이 React 컴포넌트 사용에 대한 예제와 자세한 내용은 컴포넌트 데모 페이지를 방문해보세요:

Import (불러오기)

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

Props (속성)

Name Type Default Required Description
absolute bool false No
children node - No
classes object - No Override or extend the styles applied to the component.
component elementType - No
flexItem bool false No
orientation 'horizontal' | 'vertical' 'horizontal' No
sx Array<func | object | bool> | func | object - No The system prop that allows defining system overrides as well as additional CSS styles.
textAlign 'center' | 'left' | 'right' 'center' No
variant 'fullWidth' | 'inset' | 'middle' | string 'fullWidth' No

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

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

Theme default props (테마 기본 props)

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

CSS

Rule name (규칙 이름)

Global class Rule name Description
- absolute Styles applied to the root element if absolute={true}.
- flexItem Styles applied to the root element if flexItem={true}.
- fullWidth Styles applied to the root element if variant="fullWidth".
- inset Styles applied to the root element if variant="inset".
- middle Styles applied to the root element if variant="middle".
- root Styles applied to the root element.
- textAlignLeft Styles applied to the root element if textAlign="left" orientation="horizontal".
- textAlignRight Styles applied to the root element if textAlign="right" orientation="horizontal".
- vertical Styles applied to the root element if orientation="vertical".
- withChildren Styles applied to the root element if divider have text.
- wrapper Styles applied to the span children element if orientation="horizontal".
- wrapperVertical Styles applied to the span children element if orientation="vertical".

Source code (소스 코드)

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

List API (List API)

Demos (데모)

이 React 컴포넌트 사용에 대한 예제와 자세한 내용은 컴포넌트 데모 페이지를 방문해보세요:

Import (불러오기)

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

Props (속성)

Name Type Default Required Description
children node - No
classes object - No Override or extend the styles applied to the component.
component elementType - No
dense bool false No
disablePadding bool false No
subheader node - No
sx Array<func | object | bool> | func | object - No The system prop that allows defining system overrides as well as additional CSS styles.

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

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

Theme default props (테마 기본 props)

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

CSS

Rule name (규칙 이름)

Global class Rule name Description
- dense Styles applied to the root element if dense.
- padding Styles applied to the root element unless disablePadding={true}.
- root Styles applied to the root element.
- subheader Styles applied to the root element if a subheader is provided.

Source code (소스 코드)

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

ListItem API (ListItem API)

Demos (데모)

이 React 컴포넌트 사용에 대한 예제와 자세한 내용은 컴포넌트 데모 페이지를 방문해보세요:

Import (불러오기)

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

Props (속성)

Name Type Default Required Description
alignItems 'center' | 'flex-start' 'center' No
children node - No
classes object - No Override or extend the styles applied to the component.
component elementType - No
dense bool false No
disableGutters bool false No
disablePadding bool false No
divider bool false No
secondaryAction node - No
slotProps { root?: func | object, secondaryAction?: func | object } {} No
slots { root?: elementType, secondaryAction?: elementType } {} No
sx Array<func | object | bool> | func | object - No The system prop that allows defining system overrides as well as additional CSS styles.

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

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

Theme default props (테마 기본 props)

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

CSS

Rule name (규칙 이름)

Global class Rule name Description
- alignItemsFlexStart Styles applied to the component element if alignItems="flex-start".
- dense Styles applied to the component element if dense.
- divider Styles applied to the inner component element if divider={true}.
- gutters Styles applied to the inner component element unless disableGutters={true}.
- padding Styles applied to the root element unless disablePadding={true}.
- root Styles applied to the root element.
- secondaryAction Styles applied to the secondary action element.

Source code (소스 코드)

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

ListItemAvatar API (ListItemAvatar API)

Demos (데모)

이 React 컴포넌트 사용에 대한 예제와 자세한 내용은 컴포넌트 데모 페이지를 방문해보세요:

Import (불러오기)

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

Props (속성)

Name Type Default Required Description
children node - No
classes object - No Override or extend the styles applied to the component.
sx Array<func | object | bool> | func | object - No The system prop that allows defining system overrides as well as additional CSS styles.

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

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

Theme default props (테마 기본 props)

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

CSS

Rule name (규칙 이름)

Global class Rule name Description
- alignItemsFlexStart Styles applied to the root element when the parent ListItem uses alignItems="flex-start".
- root Styles applied to the root element.

Source code (소스 코드)

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

ListItemButton API (ListItemButton API)

Demos (데모)

이 React 컴포넌트 사용에 대한 예제와 자세한 내용은 컴포넌트 데모 페이지를 방문해보세요:

Import (불러오기)

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

Props (속성)

Name Type Default Required Description
alignItems 'center' | 'flex-start' 'center' No
autoFocus bool false No
children node - No
classes object - No Override or extend the styles applied to the component.
component elementType - No
dense bool false No
disabled bool false No
disableGutters bool false No
divider bool false No
focusVisibleClassName string - No
selected bool false No
sx Array<func | object | bool> | func | object - No The system prop that allows defining system overrides as well as additional CSS styles.

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

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

Inheritance (상속)

위에 명시적으로 문서화되지는 않았지만, ButtonBase 컴포넌트의 props도 ListItemButton에서 사용할 수 있어요.

Theme default props (테마 기본 props)

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

CSS

Rule name (규칙 이름)

Global class Rule name Description
- alignItemsFlexStart Styles applied to the component element if alignItems="flex-start".
- dense Styles applied to the component element if dense.
.Mui-disabled - State class applied to the inner component element if disabled={true}.
- divider Styles applied to the inner component element if divider={true}.
.Mui-focusVisible - State class applied to the component's focusVisibleClassName prop.
- gutters Styles applied to the inner component element unless disableGutters={true}.
- root Styles applied to the root element.
.Mui-selected - State class applied to the root element if selected={true}.

Source code (소스 코드)

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

ListItemIcon API (ListItemIcon API)

Demos (데모)

이 React 컴포넌트 사용에 대한 예제와 자세한 내용은 컴포넌트 데모 페이지를 방문해보세요:

Import (불러오기)

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

Props (속성)

Name Type Default Required Description
children node - No
classes object - No Override or extend the styles applied to the component.
sx Array<func | object | bool> | func | object - No The system prop that allows defining system overrides as well as additional CSS styles.

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

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

Theme default props (테마 기본 props)

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

CSS

Rule name (규칙 이름)

Global class Rule name Description
- alignItemsFlexStart Styles applied to the root element when the parent ListItem uses alignItems="flex-start".
- root Styles applied to the root element.

Source code (소스 코드)

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

ListItemSecondaryAction API (ListItemSecondaryAction API)

Demos (데모)

이 React 컴포넌트 사용에 대한 예제와 자세한 내용은 컴포넌트 데모 페이지를 방문해보세요:

Import (불러오기)

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

Props (속성)

Name Type Default Required Description
children node - No
classes object - No Override or extend the styles applied to the component.
component elementType - No
sx Array<func | object | bool> | func | object - No The system prop that allows defining system overrides as well as additional CSS styles.

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

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

Theme default props (테마 기본 props)

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

CSS

Rule name (규칙 이름)

Global class Rule name Description
- disableGutters Styles applied to the root element when the parent ListItem has disableGutters={true}.
- root Styles applied to the root element.

Source code (소스 코드)

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

ListItemText API (ListItemText API)

Demos (데모)

이 React 컴포넌트 사용에 대한 예제와 자세한 내용은 컴포넌트 데모 페이지를 방문해보세요:

Import (불러오기)

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

Props (속성)

Name Type Default Required Description
children node - No
classes object - No Override or extend the styles applied to the component.
disableTypography bool false No
inset bool false No
primary node - No
secondary node - No
slotProps { primary?: func | object, root?: func | object, secondary?: func | object } {} No
slots { primary?: elementType, root?: elementType, secondary?: elementType } {} No
sx Array<func | object | bool> | func | object - No The system prop that allows defining system overrides as well as additional CSS styles.

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

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

Theme default props (테마 기본 props)

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

Slots (슬롯)

Name Default Class Description
root 'div' .MuiListItemText-root The component that renders the root slot.
primary Typography .MuiListItemText-primary The component that renders the primary slot.
secondary Typography .MuiListItemText-secondary The component that renders the secondary slot.

CSS

Rule name (규칙 이름)

Global class Rule name Description
- dense Styles applied to the Typography component if dense.
- inset Styles applied to the root element if inset={true}.
- multiline Styles applied to the Typography component if primary and secondary are set.

Source code (소스 코드)

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

ListSubheader API (ListSubheader API)

Demos (데모)

이 React 컴포넌트 사용에 대한 예제와 자세한 내용은 컴포넌트 데모 페이지를 방문해보세요:

Import (불러오기)

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

Props (속성)

Name Type Default Required Description
children node - No
classes object - No Override or extend the styles applied to the component.
color 'default' | 'inherit' | 'primary' 'default' No
component elementType - No
disableGutters bool false No
disableSticky bool false No
inset bool false No
sx Array<func | object | bool> | func | object - No The system prop that allows defining system overrides as well as additional CSS styles.

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

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

Theme default props (테마 기본 props)

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

CSS

Rule name (규칙 이름)

Global class Rule name Description
- colorInherit Styles applied to the root element if color="inherit".
- colorPrimary Styles applied to the root element if color="primary".
- gutters Styles applied to the inner component element unless disableGutters={true}.
- inset Styles applied to the root element if inset={true}.
- root Styles applied to the root element.
- sticky Styles applied to the root element unless disableSticky={true}.

Source code (소스 코드)

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

더 알아보기 (Learn more)