Badge
Badge (배지)
Badge는 자식의 오른쪽 상단에 작은 배지를 생성해요. 알림 개수나 상태 표시처럼 부가적인 정보를 전달할 때 유용하답니다.
출처: 문서
본문
Usage guidelines (사용 지침)
- 보조 상태 표시에 배지를 사용하세요: 기존 컨트롤이나 항목을 업데이트하는 짧은 개수나 컴팩트한 상태(예: 받은 편지함 버튼의 안 읽은 메시지 수)에 배지를 사용해요. 상태가 그 자체로 중요하다면 배지만에 의존하지 말고 UI에 직접 표시해요.
- 배지를 소유한 요소에 라벨을 지정하세요: 배지는 다른 요소에 묶인 시각적 단서이므로, 그 의미는 해당 요소의 접근 가능한 이름(accessible name)의 일부가 되어야 해요. 예를 들어 대상 요소에
aria-label="Inbox"대신aria-label="Inbox, 4 unread messages"를 사용해요. - 단순 상태에는 점 배지를 사용하세요: 점 배지(dot badge)는 텍스트나 숫자를 표시하지 않으므로, 주변 UI가 상태(예:
Online또는Unread)를 명확하게 만드는 경우에만 사용해요.
import IconButton from '@mui/material/IconButton';
import Badge from '@mui/material/Badge';
import MailIcon from '@mui/icons-material/Mail';
const maxVisibleNotifications = 99;
const unreadNotificationsCount = 100;
function getUnreadNotificationsLabel(count: number) {
if (count === 0) {
return 'show no unread notifications';
}
if (count > maxVisibleNotifications) {
return `show more than ${maxVisibleNotifications} unread notifications`;
}
return `show ${count} unread notification${count === 1 ? '' : 's'}`;
}
export default function BadgeIntro() {
const label = getUnreadNotificationsLabel(unreadNotificationsCount);
return (
<IconButton aria-label={label}>
<Badge
badgeContent={unreadNotificationsCount}
color="secondary"
max={maxVisibleNotifications}
>
<MailIcon />
</Badge>
</IconButton>
);
}
이 데모는 Badge가 있는 ListItemButton에 동일한 패턴을 적용해요: 보이는 개수를 항목의 접근 가능한 이름에 포함시켜 주변 UI 맥락에서 발음되도록 해요.
import Badge from '@mui/material/Badge';
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 Paper from '@mui/material/Paper';
import DraftsIcon from '@mui/icons-material/Drafts';
import InboxIcon from '@mui/icons-material/Inbox';
import SendIcon from '@mui/icons-material/Send';
const unreadMessagesCount = 4;
export default function BadgeListItem() {
return (
<Paper variant="outlined" sx={{ width: 320, maxWidth: '100%' }}>
<List component="nav" aria-label="mail folders" sx={{ py: 0 }}>
<ListItemButton
selected
aria-current="page"
aria-label={`Inbox, ${unreadMessagesCount} unread messages`}
>
<ListItemIcon>
<Badge badgeContent={unreadMessagesCount} color="primary">
<InboxIcon />
</Badge>
</ListItemIcon>
<ListItemText primary="Inbox" />
</ListItemButton>
<ListItemButton>
<ListItemIcon>
<SendIcon />
</ListItemIcon>
<ListItemText primary="Sent" />
</ListItemButton>
<ListItemButton>
<ListItemIcon>
<DraftsIcon />
</ListItemIcon>
<ListItemText primary="Drafts" />
</ListItemButton>
</List>
</Paper>
);
}
Badge content (배지 내용)
badgeContent를 사용해서 감싼 요소에 짧은 개수 또는 라벨을 추가해요.
import Badge from '@mui/material/Badge';
import IconButton from '@mui/material/IconButton';
import MailIcon from '@mui/icons-material/Mail';
export default function SimpleBadge() {
return (
<IconButton aria-label="show 4 unread messages">
<Badge badgeContent={4} color="primary">
<MailIcon />
</Badge>
</IconButton>
);
}
Dot badge (점 배지)
개수 없이 컴팩트한 상태 표시를 하려면 variant="dot"을 사용해요.
import IconButton from '@mui/material/IconButton';
import Badge from '@mui/material/Badge';
import NotificationsIcon from '@mui/icons-material/Notifications';
export default function DotBadge() {
return (
<IconButton aria-label="show new notifications">
<Badge color="secondary" variant="dot">
<NotificationsIcon />
</Badge>
</IconButton>
);
}
Visibility (가시성)
invisible prop으로 배지 가시성을 제어해요.
import * as React from 'react';
import Stack from '@mui/material/Stack';
import Badge from '@mui/material/Badge';
import IconButton from '@mui/material/IconButton';
import Switch from '@mui/material/Switch';
import FormControlLabel from '@mui/material/FormControlLabel';
import MailIcon from '@mui/icons-material/Mail';
const unreadMessagesCount = 4;
export default function BadgeVisibility() {
const [invisible, setInvisible] = React.useState(false);
const handleBadgeVisibility = () => {
setInvisible((previousInvisible) => !previousInvisible);
};
return (
<Stack direction="row" spacing={3} sx={{ alignItems: 'center' }}>
<IconButton
aria-label={
invisible
? 'open inbox'
: `open inbox, ${unreadMessagesCount} unread messages`
}
>
<Badge
color="secondary"
badgeContent={unreadMessagesCount}
invisible={invisible}
>
<MailIcon />
</Badge>
</IconButton>
<FormControlLabel
control={<Switch checked={!invisible} onChange={handleBadgeVisibility} />}
label="Show unread count"
/>
</Stack>
);
}
badgeContent가 0이면 배지가 자동으로 숨겨져요. 인터페이스에서 0이 의미 있을 때는 showZero prop으로 이를 오버라이드해요.
import Stack from '@mui/material/Stack';
import Badge from '@mui/material/Badge';
import IconButton from '@mui/material/IconButton';
import MailIcon from '@mui/icons-material/Mail';
export default function ShowZeroBadge() {
return (
<Stack spacing={2} direction="row">
<IconButton aria-label="show no unread messages">
<Badge color="secondary" badgeContent={0}>
<MailIcon />
</Badge>
</IconButton>
<IconButton aria-label="show 0 unread messages">
<Badge color="secondary" badgeContent={0} showZero>
<MailIcon />
</Badge>
</IconButton>
</Stack>
);
}
Maximum value (최대값)
큰 숫자 값을 상한선으로 제한하려면 max prop을 사용해요.
import Stack from '@mui/material/Stack';
import Badge from '@mui/material/Badge';
import IconButton from '@mui/material/IconButton';
import MailIcon from '@mui/icons-material/Mail';
export default function BadgeMax() {
return (
<Stack spacing={2} direction="row">
<IconButton aria-label="show 99 unread messages">
<Badge color="secondary" badgeContent={99}>
<MailIcon />
</Badge>
</IconButton>
<IconButton aria-label="show more than 99 unread messages">
<Badge color="secondary" badgeContent={100}>
<MailIcon />
</Badge>
</IconButton>
<IconButton aria-label="show more than 999 unread messages">
<Badge color="secondary" badgeContent={1000} max={999}>
<MailIcon />
</Badge>
</IconButton>
</Stack>
);
}
Customization (커스터마이징)
Color (색상)
color prop을 사용해서 테마 팔레트 색상을 배지에 적용해요.
import Badge from '@mui/material/Badge';
import Stack from '@mui/material/Stack';
import IconButton from '@mui/material/IconButton';
import CalendarMonthIcon from '@mui/icons-material/CalendarMonth';
import FolderOpenIcon from '@mui/icons-material/FolderOpen';
import ReportProblemOutlinedIcon from '@mui/icons-material/ReportProblemOutlined';
export default function ColorBadge() {
return (
<Stack spacing={2} direction="row">
<IconButton aria-label="show 8 shared files">
<Badge badgeContent={8} color="primary">
<FolderOpenIcon />
</Badge>
</IconButton>
<IconButton aria-label="show 2 confirmed events">
<Badge badgeContent={2} color="success">
<CalendarMonthIcon />
</Badge>
</IconButton>
<IconButton aria-label="show 1 critical alert">
<Badge badgeContent={1} color="error">
<ReportProblemOutlinedIcon />
</Badge>
</IconButton>
</Stack>
);
}
Badge alignment (배지 정렬)
anchorOrigin prop을 사용해서 배지를 감싼 요소의 어느 모서리로든 이동할 수 있어요.
import * as React from 'react';
import Badge from '@mui/material/Badge';
import FormControl from '@mui/material/FormControl';
import FormControlLabel from '@mui/material/FormControlLabel';
import FormLabel from '@mui/material/FormLabel';
import Radio from '@mui/material/Radio';
import RadioGroup from '@mui/material/RadioGroup';
import Box from '@mui/material/Box';
import IconButton from '@mui/material/IconButton';
import MailIcon from '@mui/icons-material/Mail';
import { HighlightedCode } from '@mui/internal-core-docs/HighlightedCode';
type BadgeVerticalOrigin = 'top' | 'bottom';
type BadgeHorizontalOrigin = 'right' | 'left';
export default function BadgeAlignment() {
const [horizontal, setHorizontal] = React.useState<BadgeHorizontalOrigin>('right');
const [vertical, setVertical] = React.useState<BadgeVerticalOrigin>('top');
const handleHorizontalChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setHorizontal(event.target.value as BadgeHorizontalOrigin);
};
const handleVerticalChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setVertical(event.target.value as BadgeVerticalOrigin);
};
const jsx = `
<IconButton aria-label="show 12 unread messages">
<Badge
badgeContent={12}
color="secondary"
anchorOrigin={{
vertical: '${vertical}',
horizontal: '${horizontal}',
}}
>
<MailIcon />
</Badge>
</IconButton>
`;
return (
<Box sx={{ width: '100%' }}>
<Box
sx={{
display: 'flex',
justifyContent: 'center',
'& fieldset': {
margin: 3,
},
}}
>
<FormControl component="fieldset">
<FormLabel component="legend">Vertical</FormLabel>
<RadioGroup
name="vertical"
value={vertical}
onChange={handleVerticalChange}
>
<FormControlLabel value="top" control={<Radio />} label="Top" />
<FormControlLabel value="bottom" control={<Radio />} label="Bottom" />
</RadioGroup>
</FormControl>
<FormControl component="fieldset">
<FormLabel component="legend">Horizontal</FormLabel>
<RadioGroup
name="horizontal"
value={horizontal}
onChange={handleHorizontalChange}
>
<FormControlLabel value="right" control={<Radio />} label="Right" />
<FormControlLabel value="left" control={<Radio />} label="Left" />
</RadioGroup>
</FormControl>
</Box>
<Box
sx={{
display: 'flex',
justifyContent: 'center',
color: 'action.active',
'& > *': {
margin: 2,
},
}}
>
<IconButton aria-label="show unread messages">
<Badge
color="secondary"
variant="dot"
anchorOrigin={{
horizontal,
vertical,
}}
>
<MailIcon />
</Badge>
</IconButton>
<IconButton aria-label="show 1 unread message">
<Badge
color="secondary"
badgeContent={1}
anchorOrigin={{
horizontal,
vertical,
}}
>
<MailIcon />
</Badge>
</IconButton>
<IconButton aria-label="show 12 unread messages">
<Badge
color="secondary"
badgeContent={12}
anchorOrigin={{
horizontal,
vertical,
}}
>
<MailIcon />
</Badge>
</IconButton>
<IconButton aria-label="show more than 99 unread messages">
<Badge
color="secondary"
badgeContent={123}
anchorOrigin={{
horizontal,
vertical,
}}
>
<MailIcon />
</Badge>
</IconButton>
<IconButton aria-label="show more than 999 unread messages">
<Badge
color="secondary"
max={999}
badgeContent={1337}
anchorOrigin={{
horizontal,
vertical,
}}
>
<MailIcon />
</Badge>
</IconButton>
</Box>
<HighlightedCode code={jsx} language="jsx" />
</Box>
);
}
Badge overlap (배지 겹침)
감싼 요소가 원형(circular)일 때 overlap prop을 사용해요.
import Box from '@mui/material/Box';
import Stack from '@mui/material/Stack';
import Badge from '@mui/material/Badge';
const shapeSize = 32;
export default function BadgeOverlap() {
return (
<Stack spacing={3} direction="row">
<Badge color="secondary" badgeContent={1}>
<Rectangle />
</Badge>
<Badge color="secondary" variant="dot">
<Rectangle />
</Badge>
<Badge color="secondary" overlap="circular" badgeContent={1}>
<Circle />
</Badge>
<Badge color="secondary" overlap="circular" variant="dot">
<Circle />
</Badge>
</Stack>
);
}
function Rectangle() {
return (
<Box
component="span"
sx={{ bgcolor: 'primary.main', width: shapeSize, height: shapeSize }}
/>
);
}
function Circle() {
return (
<Box
component="span"
sx={{
bgcolor: 'primary.main',
width: shapeSize,
height: shapeSize,
borderRadius: '50%',
}}
/>
);
}
Custom styles (커스텀 스타일)
테마 스타일 오버라이드, sx prop, 또는 styled()을 사용해서 배지를 커스터마이즈할 수 있어요. 자세한 내용은 커스터마이징 가이드에서 확인해요.
import Badge from '@mui/material/Badge';
import Avatar from '@mui/material/Avatar';
import List from '@mui/material/List';
import ListItemAvatar from '@mui/material/ListItemAvatar';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemText from '@mui/material/ListItemText';
import Paper from '@mui/material/Paper';
import { styled } from '@mui/material/styles';
type ContactStatus = 'online' | 'offline';
const statusLabels: Record<ContactStatus, string> = {
online: 'Online',
offline: 'Offline',
};
const contacts = [
{ name: 'Remy Sharp', initials: 'R', status: 'online' },
{ name: 'Travis Howard', initials: 'T', status: 'offline' },
{ name: 'Cindy Baker', initials: 'C', status: 'online' },
] as const;
const ContactStatusBadge = styled(Badge, {
shouldForwardProp: (prop) => prop !== 'status',
})<{ status: ContactStatus }>(({ theme, status }) => {
const themePalette = (theme.vars ?? theme).palette;
const offlineBadgeColor = theme.vars
? theme.vars.palette.Avatar.defaultBg
: theme.palette.grey[400];
return {
'& .MuiBadge-badge': {
height: 10,
minWidth: 10,
border: `1px solid ${themePalette.grey[300]}`,
boxShadow: `0 0 0 2px ${themePalette.background.paper}`,
...(status === 'offline' && {
backgroundColor: offlineBadgeColor,
...(theme.vars
? {}
: theme.applyStyles('dark', {
backgroundColor: theme.palette.grey[600],
})),
}),
},
};
});
export default function CustomizedBadges() {
return (
<Paper variant="outlined" sx={{ width: 320, maxWidth: '100%' }}>
<List component="nav" aria-label="contacts" sx={{ py: 0 }}>
{contacts.map((contact) => {
const statusLabel = statusLabels[contact.status];
return (
<ListItemButton
key={contact.name}
aria-label={`${contact.name}, ${contact.status}`}
>
<ListItemAvatar>
<ContactStatusBadge
status={contact.status}
color={contact.status === 'online' ? 'success' : 'default'}
variant="dot"
overlap="circular"
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
>
<Avatar>{contact.initials}</Avatar>
</ContactStatusBadge>
</ListItemAvatar>
<ListItemText primary={contact.name} secondary={statusLabel} />
</ListItemButton>
);
})}
</List>
</Paper>
);
}
Badge API (Badge API)
Demos (데모)
이 React 컴포넌트 사용에 대한 예제와 자세한 내용은 컴포넌트 데모 페이지를 방문해보세요:
Import (불러오기)
import Badge from '@mui/material/Badge';
// or
import { Badge } from '@mui/material';
Props (속성)
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
| anchorOrigin | { horizontal?: 'left' | 'right', vertical?: 'bottom' | 'top' } |
{\n vertical: 'top',\n horizontal: 'right',\n} |
No | |
| badgeContent | node |
- | No | |
| children | node |
- | No | |
| classes | object |
- | No | Override or extend the styles applied to the component. |
| color | 'default' | 'primary' | 'secondary' | 'error' | 'info' | 'success' | 'warning' | string |
'default' |
No | |
| component | elementType |
- | No | |
| invisible | bool |
false |
No | |
| max | number |
99 |
No | |
| overlap | 'circular' | 'rectangular' |
'rectangular' |
No | |
| showZero | bool |
false |
No | |
| slotProps | { badge?: func | object, root?: func | object } |
{} |
No | |
| slots | { badge?: elementType, root?: elementType } |
{} |
No | |
| sx | Array<func | object | bool> | func | object |
- | No | The system prop that allows defining system overrides as well as additional CSS styles. |
| variant | 'dot' | 'standard' | string |
'standard' |
No |
Note: The
refis forwarded to the root element (HTMLSpanElement).
Any other props supplied will be provided to the root element (native element).
Theme default props (테마 기본 props)
MuiBadge을 사용해서 테마로 이 컴포넌트의 기본 props를 변경할 수 있어요.
Slots (슬롯)
| Name | Default | Class | Description |
|---|---|---|---|
| root | span |
.MuiBadge-root |
The component that renders the root. |
| badge | span |
.MuiBadge-badge |
The component that renders the badge. |
CSS
Rule name (규칙 이름)
| Global class | Rule name | Description |
|---|---|---|
| - | anchorOriginBottomLeft | Styles applied to the badge span element if anchorOrigin={{ 'bottom', 'left' }}. |
| - | anchorOriginBottomLeftCircular | Styles applied to the badge span element if anchorOrigin={{ 'bottom', 'left' }} overlap="circular". |
| - | anchorOriginBottomLeftRectangular | Styles applied to the badge span element if anchorOrigin={{ 'bottom', 'left' }} overlap="rectangular". |
| - | anchorOriginBottomRight | Styles applied to the badge span element if anchorOrigin={{ 'bottom', 'right' }}. |
| - | anchorOriginBottomRightCircular | Styles applied to the badge span element if anchorOrigin={{ 'bottom', 'right' }} overlap="circular". |
| - | anchorOriginBottomRightRectangular | Styles applied to the badge span element if anchorOrigin={{ 'bottom', 'right' }} overlap="rectangular". |
| - | anchorOriginTopLeft | Styles applied to the badge span element if anchorOrigin={{ 'top', 'left' }}. |
| - | anchorOriginTopLeftCircular | Styles applied to the badge span element if anchorOrigin={{ 'top', 'left' }} overlap="circular". |
| - | anchorOriginTopLeftRectangular | Styles applied to the badge span element if anchorOrigin={{ 'top', 'left' }} overlap="rectangular". |
| - | anchorOriginTopRight | Styles applied to the badge span element if anchorOrigin={{ 'top', 'right' }}. |
| - | anchorOriginTopRightCircular | Styles applied to the badge span element if anchorOrigin={{ 'top', 'right' }} overlap="circular". |
| - | anchorOriginTopRightRectangular | Styles applied to the badge span element if anchorOrigin={{ 'top', 'right' }} overlap="rectangular". |
| - | colorError | Styles applied to the badge span element if color="error". |
| - | colorInfo | Styles applied to the badge span element if color="info". |
| - | colorPrimary | Styles applied to the badge span element if color="primary". |
| - | colorSecondary | Styles applied to the badge span element if color="secondary". |
| - | colorSuccess | Styles applied to the badge span element if color="success". |
| - | colorWarning | Styles applied to the badge span element if color="warning". |
| - | dot | Styles applied to the badge span element if variant="dot". |
| - | invisible | State class applied to the badge span element if invisible={true}. |
| - | overlapCircular | Styles applied to the badge span element if overlap="circular". |
| - | overlapRectangular | Styles applied to the badge span element if overlap="rectangular". |
| - | standard | Styles applied to the badge span element if variant="standard". |
Source code (소스 코드)
이 페이지에서 원하는 정보를 찾지 못했다면, 더 자세한 내용을 위해 컴포넌트 구현을 살펴보는 것을 고려해보세요.
더 알아보기 (Learn more)
- Badge 컴포넌트 데모 — 사용 예시와 자세한 내용
- 커스터마이징 가이드 — 테마 스타일 오버라이드,
sxprop,styled()사용법