Reference
Lists
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.
Introduction
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:
- List: a wrapper for list items. Renders as a
<ul className="space-y-16">
by default. - List Item: a common list item. Renders as an
<li>
by default. - List Item Button: an action element to be used inside a list item.
- List Item Icon: an icon to be used inside of a list item.
- List Item Avatar: an avatar to be used inside of a list item.
- List Item Text: a container inside a list item, used to display text content.
- List Divider: a separator between list items.
- List Subheader: a label for a nested list.
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.
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
- Photos
Jan 9, 2014
- Work
Jan 7, 2014
- Vacation
July 20, 2014
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> ); }
Interactive
Below is an interactive demo that lets you explore the visual results of the different settings:
Text only
- Single-line item
- Single-line item
- Single-line item
Icon with text
- Single-line item
- Single-line item
- Single-line item
Avatar with text
- Single-line item
- Single-line item
- Single-line item
Avatar with text and icon
- Single-line item
- Single-line item
- Single-line item
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> ); }
Selected 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
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:- Brunch this weekend?
Ali Connors — I'll be in your neighborhood doing errands this…
- Summer BBQ
to Scott, Alex, Jennifer — Wish I could come, but I'm out of town this…
- Oui Oui
Sandra Adams — Do you have Paris recommendations? Have you ever…
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="/material-ui-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="/material-ui-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="/material-ui-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
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.
- Line item 1
- Line item 2
- Line item 3
- Line item 4
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.
- Line item 1
- Line item 2
- Line item 3
- Line item 4
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={`/material-ui-static/images/avatar/${value + 1}.jpg`} /> </ListItemAvatar> <ListItemText id={labelId} primary={`Line item ${value + 1}`} /> </ListItemButton> </ListItem> ); })} </List> ); }
Switch
The switch is the secondary action and a separate target.
- Settings
- Wi-Fi
- Bluetooth
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> ); }
Sticky subheader
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.
- I'm sticky 0
- Item 0
- Item 1
- Item 2
- I'm sticky 1
- Item 0
- Item 1
- Item 2
- I'm sticky 2
- Item 0
- Item 1
- Item 2
- I'm sticky 3
- Item 0
- Item 1
- Item 2
- I'm sticky 4
- Item 0
- Item 1
- Item 2
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> ); }
Inset List Item
The
inset
prop enables a list item that does not have a leading icon or avatar to align correctly with items that do.- Chelsea Otakan
- Eric Hoffman
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> ); }
Gutterless list
When rendering a list within a component that defines its own gutters,
ListItem
gutters can be disabled with disableGutters
.- Line item 1
- Line item 2
- Line item 3
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> ); }
Virtualized 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.Item 1
Item 2
Item 3
Item 4
Item 5
Item 6
Item 7
Item 8
Item 9
Item 10
Item 11
Item 12
Item 13
Item 14
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.
Customization
Here are some examples of customizing the component. You can learn more about this in theoverrides 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> ); }