Lists are continuous, vertical indexes of text or images.
Lists are a continuous group of text or images. They are composed of items containing primary and supplemental actions, which are represented by icons and text.
Lists present information in a concise, easy-to-follow format through a continuous, vertical index of text or images.
Material UI Lists are implemented using a collection of related components:
<ul>
by default.<li>
by default.import * as React from 'react';
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>
);
}
The last item of the previous demo shows how you can render a link:
<ListItemButton component="a" href="#simple-list">
<ListItemText primary="Spam" />
</ListItemButton>
You can find a demo with React Router following this section of the documentation.
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
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>
);
}
import * as React from 'react';
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>
);
}
Below is an interactive demo that lets you explore the visual results of the different settings:
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.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 item 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 item 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 item 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 item 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>
);
}
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>
);
}
When displaying three lines or more, the avatar is not aligned at the top.
You should set the alignItems="flex-start"
prop to align the avatar at the top, following the Material Design guidelines:
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>
);
}
A checkbox can either be a primary action or a secondary action.
The checkbox is the primary action and the state indicator for the list item. The comment button is a secondary action and a separate target.
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
inputProps={{ 'aria-labelledby': labelId }}
/>
</ListItemIcon>
<ListItemText id={labelId} primary={`Line item ${value + 1}`} />
</ListItemButton>
</ListItem>
);
})}
</List>
);
}
The checkbox is the secondary action for the list item and a separate target.
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)}
inputProps={{ '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>
);
}
The switch is the secondary action and a separate target.
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')}
inputProps={{
'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')}
inputProps={{
'aria-labelledby': 'switch-list-label-bluetooth',
}}
/>
</ListItem>
</List>
);
}
Upon scrolling, subheaders remain pinned to the top of the screen until pushed off screen by the next subheader. This feature relies on CSS sticky positioning.
import * as React from 'react';
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>
);
}
The inset
prop enables a list item that does not have a leading icon or avatar to align correctly with items that do.
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 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>
);
}
When rendering a list within a component that defines its own gutters, ListItem
gutters can be disabled with disableGutters
.
import * as React from 'react';
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>
);
}
In the following example, we demonstrate how to use react-window with the List
component.
It renders 200 rows and can easily handle more.
Virtualization helps with performance issues.
import * as React from 'react';
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 { FixedSizeList, ListChildComponentProps } from 'react-window';
function renderRow(props: ListChildComponentProps) {
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' }}
>
<FixedSizeList
height={400}
width={360}
itemSize={46}
itemCount={200}
overscanCount={5}
>
{renderRow}
</FixedSizeList>
</Box>
);
}
The use of react-window when possible is encouraged. If this library doesn’t cover your use case, you should consider using alternatives like react-virtuoso.
Here are some examples of customizing the component. You can learn more about this in the overrides documentation page.
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"
primaryTypographyProps={{
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"
primaryTypographyProps={{
color: 'primary',
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"
primaryTypographyProps={{
fontSize: 15,
fontWeight: 'medium',
lineHeight: '20px',
mb: '2px',
}}
secondary="Authentication, Firestore Database, Realtime Database, Storage, Hosting, Functions, and Machine Learning"
secondaryTypographyProps={{
noWrap: true,
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}
primaryTypographyProps={{ fontSize: 14, fontWeight: 'medium' }}
/>
</ListItemButton>
))}
</Box>
</FireNav>
</Paper>
</ThemeProvider>
</Box>
);
}