diff --git a/docs/data/material/components/avatars/BadgeAvatars.js b/docs/data/material/components/avatars/BadgeAvatars.js index e766d0d8983159..15096edc0cfadf 100644 --- a/docs/data/material/components/avatars/BadgeAvatars.js +++ b/docs/data/material/components/avatars/BadgeAvatars.js @@ -2,6 +2,7 @@ import { styled } from '@mui/material/styles'; import Badge from '@mui/material/Badge'; import Avatar from '@mui/material/Avatar'; import Stack from '@mui/material/Stack'; +import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile'; const StyledBadge = styled(Badge)(({ theme }) => ({ '& .MuiBadge-badge': { @@ -46,16 +47,28 @@ export default function BadgeAvatars() { anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }} variant="dot" > - + - } + badgeContent={2} + color="primary" > - + + + } + > + ); diff --git a/docs/data/material/components/avatars/BadgeAvatars.tsx b/docs/data/material/components/avatars/BadgeAvatars.tsx index e766d0d8983159..15096edc0cfadf 100644 --- a/docs/data/material/components/avatars/BadgeAvatars.tsx +++ b/docs/data/material/components/avatars/BadgeAvatars.tsx @@ -2,6 +2,7 @@ import { styled } from '@mui/material/styles'; import Badge from '@mui/material/Badge'; import Avatar from '@mui/material/Avatar'; import Stack from '@mui/material/Stack'; +import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile'; const StyledBadge = styled(Badge)(({ theme }) => ({ '& .MuiBadge-badge': { @@ -46,16 +47,28 @@ export default function BadgeAvatars() { anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }} variant="dot" > - + - } + badgeContent={2} + color="primary" > - + + + } + > + ); diff --git a/docs/data/material/components/avatars/BadgeAvatars.tsx.preview b/docs/data/material/components/avatars/BadgeAvatars.tsx.preview deleted file mode 100644 index aea45175d98672..00000000000000 --- a/docs/data/material/components/avatars/BadgeAvatars.tsx.preview +++ /dev/null @@ -1,16 +0,0 @@ - - - - - } -> - - \ No newline at end of file diff --git a/docs/data/material/components/badges/AccessibleBadges.js b/docs/data/material/components/badges/AccessibleBadges.js deleted file mode 100644 index 534768253854ed..00000000000000 --- a/docs/data/material/components/badges/AccessibleBadges.js +++ /dev/null @@ -1,23 +0,0 @@ -import IconButton from '@mui/material/IconButton'; -import Badge from '@mui/material/Badge'; -import MailIcon from '@mui/icons-material/Mail'; - -function notificationsLabel(count) { - if (count === 0) { - return 'no notifications'; - } - if (count > 99) { - return 'more than 99 notifications'; - } - return `${count} notifications`; -} - -export default function AccessibleBadges() { - return ( - - - - - - ); -} diff --git a/docs/data/material/components/badges/AccessibleBadges.tsx b/docs/data/material/components/badges/AccessibleBadges.tsx deleted file mode 100644 index 87669fe95cd323..00000000000000 --- a/docs/data/material/components/badges/AccessibleBadges.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import IconButton from '@mui/material/IconButton'; -import Badge from '@mui/material/Badge'; -import MailIcon from '@mui/icons-material/Mail'; - -function notificationsLabel(count: number) { - if (count === 0) { - return 'no notifications'; - } - if (count > 99) { - return 'more than 99 notifications'; - } - return `${count} notifications`; -} - -export default function AccessibleBadges() { - return ( - - - - - - ); -} diff --git a/docs/data/material/components/badges/AccessibleBadges.tsx.preview b/docs/data/material/components/badges/AccessibleBadges.tsx.preview deleted file mode 100644 index c25da83389c0e2..00000000000000 --- a/docs/data/material/components/badges/AccessibleBadges.tsx.preview +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/docs/data/material/components/badges/BadgeAlignment.js b/docs/data/material/components/badges/BadgeAlignment.js index 8e15b61b9ec76e..e50ab1ea2c8eab 100644 --- a/docs/data/material/components/badges/BadgeAlignment.js +++ b/docs/data/material/components/badges/BadgeAlignment.js @@ -6,6 +6,7 @@ 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'; @@ -22,12 +23,18 @@ export default function BadgeAlignment() { }; const jsx = ` - + + + + + `; return ( @@ -74,58 +81,67 @@ export default function BadgeAlignment() { }, }} > - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/data/material/components/badges/BadgeAlignment.tsx b/docs/data/material/components/badges/BadgeAlignment.tsx new file mode 100644 index 00000000000000..b6e9e326c22e28 --- /dev/null +++ b/docs/data/material/components/badges/BadgeAlignment.tsx @@ -0,0 +1,152 @@ +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('right'); + const [vertical, setVertical] = React.useState('top'); + + const handleHorizontalChange = (event: React.ChangeEvent) => { + setHorizontal(event.target.value as BadgeHorizontalOrigin); + }; + + const handleVerticalChange = (event: React.ChangeEvent) => { + setVertical(event.target.value as BadgeVerticalOrigin); + }; + + const jsx = ` + + + + + +`; + + return ( + + + + Vertical + + } label="Top" /> + } label="Bottom" /> + + + + Horizontal + + } label="Right" /> + } label="Left" /> + + + + *': { + margin: 2, + }, + }} + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +} diff --git a/docs/data/material/components/badges/BadgeIntro.js b/docs/data/material/components/badges/BadgeIntro.js new file mode 100644 index 00000000000000..b224915776a450 --- /dev/null +++ b/docs/data/material/components/badges/BadgeIntro.js @@ -0,0 +1,32 @@ +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) { + 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 ( + + + + + + ); +} diff --git a/docs/data/material/components/badges/BadgeIntro.tsx b/docs/data/material/components/badges/BadgeIntro.tsx new file mode 100644 index 00000000000000..800c9ed5cfd343 --- /dev/null +++ b/docs/data/material/components/badges/BadgeIntro.tsx @@ -0,0 +1,32 @@ +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 ( + + + + + + ); +} diff --git a/docs/data/material/components/badges/BadgeIntro.tsx.preview b/docs/data/material/components/badges/BadgeIntro.tsx.preview new file mode 100644 index 00000000000000..8ac406a232efa1 --- /dev/null +++ b/docs/data/material/components/badges/BadgeIntro.tsx.preview @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/docs/data/material/components/badges/BadgeListItem.js b/docs/data/material/components/badges/BadgeListItem.js new file mode 100644 index 00000000000000..ecad45320e4c89 --- /dev/null +++ b/docs/data/material/components/badges/BadgeListItem.js @@ -0,0 +1,44 @@ +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 ( + + + + + + + + + + + + + + + + + + + + + + + + + ); +} diff --git a/docs/data/material/components/badges/BadgeListItem.tsx b/docs/data/material/components/badges/BadgeListItem.tsx new file mode 100644 index 00000000000000..ecad45320e4c89 --- /dev/null +++ b/docs/data/material/components/badges/BadgeListItem.tsx @@ -0,0 +1,44 @@ +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 ( + + + + + + + + + + + + + + + + + + + + + + + + + ); +} diff --git a/docs/data/material/components/badges/BadgeMax.js b/docs/data/material/components/badges/BadgeMax.js index de0408b563b692..3fa8faf52d0436 100644 --- a/docs/data/material/components/badges/BadgeMax.js +++ b/docs/data/material/components/badges/BadgeMax.js @@ -1,19 +1,26 @@ 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 ( - - - - - - - - - - + + + + + + + + + + + + + + + + ); } diff --git a/docs/data/material/components/badges/BadgeMax.tsx b/docs/data/material/components/badges/BadgeMax.tsx index de0408b563b692..3fa8faf52d0436 100644 --- a/docs/data/material/components/badges/BadgeMax.tsx +++ b/docs/data/material/components/badges/BadgeMax.tsx @@ -1,19 +1,26 @@ 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 ( - - - - - - - - - - + + + + + + + + + + + + + + + + ); } diff --git a/docs/data/material/components/badges/BadgeMax.tsx.preview b/docs/data/material/components/badges/BadgeMax.tsx.preview index 00e369cb4b7c20..3f1f31c5500b37 100644 --- a/docs/data/material/components/badges/BadgeMax.tsx.preview +++ b/docs/data/material/components/badges/BadgeMax.tsx.preview @@ -1,9 +1,15 @@ - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/data/material/components/badges/BadgeOverlap.js b/docs/data/material/components/badges/BadgeOverlap.js index 78b60f85ad67c8..dae9425fd0c50a 100644 --- a/docs/data/material/components/badges/BadgeOverlap.js +++ b/docs/data/material/components/badges/BadgeOverlap.js @@ -2,28 +2,46 @@ import Box from '@mui/material/Box'; import Stack from '@mui/material/Stack'; import Badge from '@mui/material/Badge'; -const shapeStyles = { bgcolor: 'primary.main', width: 40, height: 40 }; -const shapeCircleStyles = { borderRadius: '50%' }; -const rectangle = ; -const circle = ( - -); +const shapeSize = 32; export default function BadgeOverlap() { return ( - - {rectangle} + + - - {rectangle} + + - - {circle} + + - - {circle} + + ); } + +function Rectangle() { + return ( + + ); +} + +function Circle() { + return ( + + ); +} diff --git a/docs/data/material/components/badges/BadgeOverlap.tsx b/docs/data/material/components/badges/BadgeOverlap.tsx index 02e67a6a91461e..dae9425fd0c50a 100644 --- a/docs/data/material/components/badges/BadgeOverlap.tsx +++ b/docs/data/material/components/badges/BadgeOverlap.tsx @@ -2,27 +2,46 @@ import Box from '@mui/material/Box'; import Stack from '@mui/material/Stack'; import Badge from '@mui/material/Badge'; -const shapeStyles = { bgcolor: 'primary.main', width: 40, height: 40 }; -const shapeCircleStyles = { borderRadius: '50%' }; -const rectangle = ; -const circle = ( - -); +const shapeSize = 32; + export default function BadgeOverlap() { return ( - - {rectangle} + + - - {rectangle} + + - - {circle} + + - - {circle} + + ); } + +function Rectangle() { + return ( + + ); +} + +function Circle() { + return ( + + ); +} diff --git a/docs/data/material/components/badges/BadgeOverlap.tsx.preview b/docs/data/material/components/badges/BadgeOverlap.tsx.preview index 9319a000516096..3c6615924cee05 100644 --- a/docs/data/material/components/badges/BadgeOverlap.tsx.preview +++ b/docs/data/material/components/badges/BadgeOverlap.tsx.preview @@ -1,12 +1,12 @@ - - {rectangle} + + - - {rectangle} + + - - {circle} + + - - {circle} + + \ No newline at end of file diff --git a/docs/data/material/components/badges/BadgeVisibility.js b/docs/data/material/components/badges/BadgeVisibility.js index e70cd166c14d61..16a594b0e3a397 100644 --- a/docs/data/material/components/badges/BadgeVisibility.js +++ b/docs/data/material/components/badges/BadgeVisibility.js @@ -1,69 +1,41 @@ import * as React from 'react'; -import Box from '@mui/material/Box'; +import Stack from '@mui/material/Stack'; import Badge from '@mui/material/Badge'; -import ButtonGroup from '@mui/material/ButtonGroup'; -import Button from '@mui/material/Button'; -import AddIcon from '@mui/icons-material/Add'; -import RemoveIcon from '@mui/icons-material/Remove'; -import MailIcon from '@mui/icons-material/Mail'; +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 [count, setCount] = React.useState(1); const [invisible, setInvisible] = React.useState(false); const handleBadgeVisibility = () => { - setInvisible(!invisible); + setInvisible((previousInvisible) => !previousInvisible); }; return ( - *': { - marginBottom: 2, - }, - '& .MuiBadge-root': { - marginRight: 4, - }, - }} - > -
- - - - - - - -
-
- + + + - } - label="Show Badge" - /> -
-
+ + } + label="Show unread count" + /> +
); } diff --git a/docs/data/material/components/badges/BadgeVisibility.tsx b/docs/data/material/components/badges/BadgeVisibility.tsx index e70cd166c14d61..16a594b0e3a397 100644 --- a/docs/data/material/components/badges/BadgeVisibility.tsx +++ b/docs/data/material/components/badges/BadgeVisibility.tsx @@ -1,69 +1,41 @@ import * as React from 'react'; -import Box from '@mui/material/Box'; +import Stack from '@mui/material/Stack'; import Badge from '@mui/material/Badge'; -import ButtonGroup from '@mui/material/ButtonGroup'; -import Button from '@mui/material/Button'; -import AddIcon from '@mui/icons-material/Add'; -import RemoveIcon from '@mui/icons-material/Remove'; -import MailIcon from '@mui/icons-material/Mail'; +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 [count, setCount] = React.useState(1); const [invisible, setInvisible] = React.useState(false); const handleBadgeVisibility = () => { - setInvisible(!invisible); + setInvisible((previousInvisible) => !previousInvisible); }; return ( - *': { - marginBottom: 2, - }, - '& .MuiBadge-root': { - marginRight: 4, - }, - }} - > -
- - - - - - - -
-
- + + + - } - label="Show Badge" - /> -
-
+ + } + label="Show unread count" + /> +
); } diff --git a/docs/data/material/components/badges/ColorBadge.js b/docs/data/material/components/badges/ColorBadge.js index b19bf74fbf8589..b91caeaa02bbb0 100644 --- a/docs/data/material/components/badges/ColorBadge.js +++ b/docs/data/material/components/badges/ColorBadge.js @@ -1,16 +1,28 @@ import Badge from '@mui/material/Badge'; import Stack from '@mui/material/Stack'; -import MailIcon from '@mui/icons-material/Mail'; +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 ( - - - - - - + + + + + + + + + + + + + + + ); } diff --git a/docs/data/material/components/badges/ColorBadge.tsx b/docs/data/material/components/badges/ColorBadge.tsx index b19bf74fbf8589..b91caeaa02bbb0 100644 --- a/docs/data/material/components/badges/ColorBadge.tsx +++ b/docs/data/material/components/badges/ColorBadge.tsx @@ -1,16 +1,28 @@ import Badge from '@mui/material/Badge'; import Stack from '@mui/material/Stack'; -import MailIcon from '@mui/icons-material/Mail'; +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 ( - - - - - - + + + + + + + + + + + + + + + ); } diff --git a/docs/data/material/components/badges/ColorBadge.tsx.preview b/docs/data/material/components/badges/ColorBadge.tsx.preview index b35d11d16a8b04..f2d98ba9cbee85 100644 --- a/docs/data/material/components/badges/ColorBadge.tsx.preview +++ b/docs/data/material/components/badges/ColorBadge.tsx.preview @@ -1,6 +1,15 @@ - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/data/material/components/badges/CustomizedBadges.js b/docs/data/material/components/badges/CustomizedBadges.js index 626d8b8f23c8e4..571a053c3eeece 100644 --- a/docs/data/material/components/badges/CustomizedBadges.js +++ b/docs/data/material/components/badges/CustomizedBadges.js @@ -1,23 +1,77 @@ 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'; -import IconButton from '@mui/material/IconButton'; -import ShoppingCartIcon from '@mui/icons-material/ShoppingCart'; -const StyledBadge = styled(Badge)(({ theme }) => ({ - '& .MuiBadge-badge': { - right: -3, - top: 13, - border: `2px solid ${(theme.vars ?? theme).palette.background.paper}`, - padding: '0 4px', - }, -})); +const statusLabels = { + 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' }, +]; + +const ContactStatusBadge = styled(Badge, { + shouldForwardProp: (prop) => prop !== 'status', +})(({ 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 ( - - - - - + + + {contacts.map((contact) => { + const statusLabel = statusLabels[contact.status]; + + return ( + + + + {contact.initials} + + + + + ); + })} + + ); } diff --git a/docs/data/material/components/badges/CustomizedBadges.tsx b/docs/data/material/components/badges/CustomizedBadges.tsx index 0831ae9f4ab8bd..588d45a8125a5b 100644 --- a/docs/data/material/components/badges/CustomizedBadges.tsx +++ b/docs/data/material/components/badges/CustomizedBadges.tsx @@ -1,23 +1,79 @@ -import Badge, { BadgeProps } from '@mui/material/Badge'; +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'; -import IconButton from '@mui/material/IconButton'; -import ShoppingCartIcon from '@mui/icons-material/ShoppingCart'; -const StyledBadge = styled(Badge)(({ theme }) => ({ - '& .MuiBadge-badge': { - right: -3, - top: 13, - border: `2px solid ${(theme.vars ?? theme).palette.background.paper}`, - padding: '0 4px', - }, -})); +type ContactStatus = 'online' | 'offline'; + +const statusLabels: Record = { + 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 ( - - - - - + + + {contacts.map((contact) => { + const statusLabel = statusLabels[contact.status]; + + return ( + + + + {contact.initials} + + + + + ); + })} + + ); } diff --git a/docs/data/material/components/badges/CustomizedBadges.tsx.preview b/docs/data/material/components/badges/CustomizedBadges.tsx.preview deleted file mode 100644 index 6e9ddc2f1b230d..00000000000000 --- a/docs/data/material/components/badges/CustomizedBadges.tsx.preview +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/docs/data/material/components/badges/DotBadge.js b/docs/data/material/components/badges/DotBadge.js index 5cd2e1d99d6580..a28e192fef3809 100644 --- a/docs/data/material/components/badges/DotBadge.js +++ b/docs/data/material/components/badges/DotBadge.js @@ -1,13 +1,13 @@ -import Box from '@mui/material/Box'; +import IconButton from '@mui/material/IconButton'; import Badge from '@mui/material/Badge'; -import MailIcon from '@mui/icons-material/Mail'; +import NotificationsIcon from '@mui/icons-material/Notifications'; export default function DotBadge() { return ( - + - + - + ); } diff --git a/docs/data/material/components/badges/DotBadge.tsx b/docs/data/material/components/badges/DotBadge.tsx index 5cd2e1d99d6580..a28e192fef3809 100644 --- a/docs/data/material/components/badges/DotBadge.tsx +++ b/docs/data/material/components/badges/DotBadge.tsx @@ -1,13 +1,13 @@ -import Box from '@mui/material/Box'; +import IconButton from '@mui/material/IconButton'; import Badge from '@mui/material/Badge'; -import MailIcon from '@mui/icons-material/Mail'; +import NotificationsIcon from '@mui/icons-material/Notifications'; export default function DotBadge() { return ( - + - + - + ); } diff --git a/docs/data/material/components/badges/DotBadge.tsx.preview b/docs/data/material/components/badges/DotBadge.tsx.preview index 18f911822424f2..7e0cbca17863f8 100644 --- a/docs/data/material/components/badges/DotBadge.tsx.preview +++ b/docs/data/material/components/badges/DotBadge.tsx.preview @@ -1,3 +1,5 @@ - - - \ No newline at end of file + + + + + \ No newline at end of file diff --git a/docs/data/material/components/badges/ShowZeroBadge.js b/docs/data/material/components/badges/ShowZeroBadge.js index 7df4e1f146aeff..8b835272ccf1bc 100644 --- a/docs/data/material/components/badges/ShowZeroBadge.js +++ b/docs/data/material/components/badges/ShowZeroBadge.js @@ -1,16 +1,21 @@ 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 ( - - - - - - - + + + + + + + + + + + ); } diff --git a/docs/data/material/components/badges/ShowZeroBadge.tsx b/docs/data/material/components/badges/ShowZeroBadge.tsx index 7df4e1f146aeff..8b835272ccf1bc 100644 --- a/docs/data/material/components/badges/ShowZeroBadge.tsx +++ b/docs/data/material/components/badges/ShowZeroBadge.tsx @@ -1,16 +1,21 @@ 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 ( - - - - - - - + + + + + + + + + + + ); } diff --git a/docs/data/material/components/badges/ShowZeroBadge.tsx.preview b/docs/data/material/components/badges/ShowZeroBadge.tsx.preview index b687e1c50d6796..fbcdb854c7f78f 100644 --- a/docs/data/material/components/badges/ShowZeroBadge.tsx.preview +++ b/docs/data/material/components/badges/ShowZeroBadge.tsx.preview @@ -1,6 +1,10 @@ - - - - - - \ No newline at end of file + + + + + + + + + + \ No newline at end of file diff --git a/docs/data/material/components/badges/SimpleBadge.js b/docs/data/material/components/badges/SimpleBadge.js index e880228abd06ea..36cf3446bfaba7 100644 --- a/docs/data/material/components/badges/SimpleBadge.js +++ b/docs/data/material/components/badges/SimpleBadge.js @@ -1,10 +1,13 @@ import Badge from '@mui/material/Badge'; +import IconButton from '@mui/material/IconButton'; import MailIcon from '@mui/icons-material/Mail'; export default function SimpleBadge() { return ( - - - + + + + + ); } diff --git a/docs/data/material/components/badges/SimpleBadge.tsx b/docs/data/material/components/badges/SimpleBadge.tsx index e880228abd06ea..36cf3446bfaba7 100644 --- a/docs/data/material/components/badges/SimpleBadge.tsx +++ b/docs/data/material/components/badges/SimpleBadge.tsx @@ -1,10 +1,13 @@ import Badge from '@mui/material/Badge'; +import IconButton from '@mui/material/IconButton'; import MailIcon from '@mui/icons-material/Mail'; export default function SimpleBadge() { return ( - - - + + + + + ); } diff --git a/docs/data/material/components/badges/SimpleBadge.tsx.preview b/docs/data/material/components/badges/SimpleBadge.tsx.preview index 390a9496070568..82329e7734c884 100644 --- a/docs/data/material/components/badges/SimpleBadge.tsx.preview +++ b/docs/data/material/components/badges/SimpleBadge.tsx.preview @@ -1,3 +1,5 @@ - - - \ No newline at end of file + + + + + \ No newline at end of file diff --git a/docs/data/material/components/badges/badges.md b/docs/data/material/components/badges/badges.md index b4e8b0ee8eb3a6..0b0a172ead7f16 100644 --- a/docs/data/material/components/badges/badges.md +++ b/docs/data/material/components/badges/badges.md @@ -12,62 +12,78 @@ githubSource: packages/mui-material/src/Badge {{"component": "@mui/internal-core-docs/ComponentLinkHeader"}} -## Basic badge +## Usage guidelines -Examples of badges containing text, using primary and secondary colors. The badge is applied to its children. +- **Use badges for supplemental status**: Use badges for short counts or compact states + that update an existing control or item, such as unread messages on an inbox button. If + the status is important on its own, show it in the UI instead of relying only on the badge. +- **Label the element that owns the badge**: A badge is a visual cue tied to another + element, so its meaning should be part of that element's accessible name. For example, + use `aria-label="Inbox, 4 unread messages"` instead of `aria-label="Inbox"` on the + target element. +- **Use dot badges for simple states**: A dot badge does not show text or a number, so use + it only when the surrounding UI makes the state clear, such as `Online` or `Unread`. -{{"demo": "SimpleBadge.js"}} +{{"demo": "BadgeIntro.js"}} -## Color +This demo applies the same pattern to a `ListItemButton` with a `Badge`: the visible +count is included in the item's accessible name so it's announced in the context of the +surrounding UI. -Use `color` prop to apply theme palette to component. +{{"demo": "BadgeListItem.js"}} -{{"demo": "ColorBadge.js"}} +## Badge content -## Customization +Use `badgeContent` to add a short count or label to the wrapped element. -Here is an example of customizing the component. -You can learn more about this in the [overrides documentation page](/material-ui/customization/how-to-customize/). +{{"demo": "SimpleBadge.js"}} -{{"demo": "CustomizedBadges.js"}} +### Dot badge -## Badge visibility +Use `variant="dot"` for a compact status indicator without a count. -The visibility of badges can be controlled using the `invisible` prop. +{{"demo": "DotBadge.js"}} + +### Visibility + +Control badge visibility with the `invisible` prop. {{"demo": "BadgeVisibility.js"}} -The badge hides automatically when `badgeContent` is zero. You can override this with the `showZero` prop. +The badge hides automatically when `badgeContent` is zero. Override this with the `showZero` +prop when zero is meaningful to the interface. {{"demo": "ShowZeroBadge.js"}} -## Maximum value +### Maximum value -You can use the `max` prop to cap the value of the badge content. +Use the `max` prop to cap large numeric values. {{"demo": "BadgeMax.js"}} -## Dot badge +## Customization -The `dot` prop changes a badge into a small dot. This can be used as a notification that something has changed without giving a count. +### Color -{{"demo": "DotBadge.js"}} +Use the `color` prop to apply theme palette colors to the badge. + +{{"demo": "ColorBadge.js"}} -## Badge overlap +### Badge alignment -You can use the `overlap` prop to place the badge relative to the corner of the wrapped element. +Use the `anchorOrigin` prop to move the badge to any corner of the wrapped element. -{{"demo": "BadgeOverlap.js"}} +{{"demo": "BadgeAlignment.js", "hideToolbar": true}} -## Badge alignment +### Badge overlap -You can use the `anchorOrigin` prop to move the badge to any corner of the wrapped element. +Use the `overlap` prop when the wrapped element is circular. -{{"demo": "BadgeAlignment.js", "hideToolbar": true}} +{{"demo": "BadgeOverlap.js"}} -## Accessibility +### Custom styles -You can't rely on the content of the badge to be announced correctly. -You should provide a full description, for instance, with `aria-label`: +Use theme style overrides, the `sx` prop, or `styled()` to customize the badge. +Learn more in the [customization guide](/material-ui/customization/how-to-customize/). -{{"demo": "AccessibleBadges.js"}} +{{"demo": "CustomizedBadges.js"}} diff --git a/docs/data/material/components/buttons/IconButtonWithBadge.js b/docs/data/material/components/buttons/IconButtonWithBadge.js index 3132aa52ada790..90c4ed142ffab8 100644 --- a/docs/data/material/components/buttons/IconButtonWithBadge.js +++ b/docs/data/material/components/buttons/IconButtonWithBadge.js @@ -12,7 +12,7 @@ const CartBadge = styled(Badge)` export default function IconButtonWithBadge() { return ( - + diff --git a/docs/data/material/components/buttons/IconButtonWithBadge.tsx b/docs/data/material/components/buttons/IconButtonWithBadge.tsx index 3132aa52ada790..90c4ed142ffab8 100644 --- a/docs/data/material/components/buttons/IconButtonWithBadge.tsx +++ b/docs/data/material/components/buttons/IconButtonWithBadge.tsx @@ -12,7 +12,7 @@ const CartBadge = styled(Badge)` export default function IconButtonWithBadge() { return ( - + diff --git a/docs/data/material/components/buttons/IconButtonWithBadge.tsx.preview b/docs/data/material/components/buttons/IconButtonWithBadge.tsx.preview index aa71bce96117c6..197f65b376bf75 100644 --- a/docs/data/material/components/buttons/IconButtonWithBadge.tsx.preview +++ b/docs/data/material/components/buttons/IconButtonWithBadge.tsx.preview @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/packages/mui-material/src/Badge/Badge.js b/packages/mui-material/src/Badge/Badge.js index 992b3bbd37b0a7..a85f5a90622e41 100644 --- a/packages/mui-material/src/Badge/Badge.js +++ b/packages/mui-material/src/Badge/Badge.js @@ -241,6 +241,9 @@ const Badge = React.forwardRef(function Badge(inProps, ref) { externalForwardedProps, ownerState, className: classes.badge, + additionalProps: { + 'aria-hidden': true, + }, }); return ( diff --git a/packages/mui-material/src/Badge/Badge.test.js b/packages/mui-material/src/Badge/Badge.test.js index 6af1357b4cdcf8..7433581862c161 100644 --- a/packages/mui-material/src/Badge/Badge.test.js +++ b/packages/mui-material/src/Badge/Badge.test.js @@ -54,6 +54,12 @@ describe('', () => { expect(container.firstChild).to.contain(screen.getByTestId('badge')); }); + it('hides the visual badge from assistive technologies by default', () => { + const { container } = render(); + + expect(findBadge(container)).to.have.attribute('aria-hidden', 'true'); + }); + it('applies customized classes', () => { const customClasses = { root: 'test-root', @@ -344,6 +350,18 @@ describe('', () => { screen.getByTestId('custom-root'); screen.getByTestId('custom-badge'); }); + + it('allows overriding the badge accessibility props', () => { + const { container } = render( + , + ); + + expect(findBadge(container)).to.have.attribute('aria-hidden', 'false'); + expect(findBadge(container)).to.have.attribute('aria-label', '10 notifications'); + }); }); it('retains anchorOrigin, content, color, max, overlap and variant when invisible is true for consistent disappearing transition', () => {