How to set selected and hover color of ListItem in MUI?

16,597

Solution 1

Below is the portion of the default ListItem styles that deals with the background color:

export const styles = (theme) => ({
  /* Styles applied to the (normally root) `component` element. May be wrapped by a `container`. */
  root: {
    '&$focusVisible': {
      backgroundColor: theme.palette.action.selected,
    },
    '&$selected, &$selected:hover': {
      backgroundColor: theme.palette.action.selected,
    },
    '&$disabled': {
      opacity: 0.5,
    },
  },
  /* Pseudo-class applied to the `component`'s `focusVisibleClassName` prop if `button={true}`. */
  focusVisible: {},
  /* Styles applied to the inner `component` element if `button={true}`. */
  button: {
    transition: theme.transitions.create('background-color', {
      duration: theme.transitions.duration.shortest,
    }),
    '&:hover': {
      textDecoration: 'none',
      backgroundColor: theme.palette.action.hover,
      // Reset on touch devices, it doesn't add specificity
      '@media (hover: none)': {
        backgroundColor: 'transparent',
      },
    },
  },
  /* Pseudo-class applied to the root element if `selected={true}`. */
  selected: {},
});

The important thing to notice is that the selected styling is done via a combination of two classes (root and selected), so if you try to override it using a single class you will not have sufficient specificity.

Below is an example showing one way to override the selected and hover states:

import React from "react";
import { makeStyles, withStyles } from "@material-ui/core/styles";
import List from "@material-ui/core/List";
import MuiListItem from "@material-ui/core/ListItem";
import ListItemIcon from "@material-ui/core/ListItemIcon";
import ListItemText from "@material-ui/core/ListItemText";
import Divider from "@material-ui/core/Divider";
import InboxIcon from "@material-ui/icons/Inbox";
import DraftsIcon from "@material-ui/icons/Drafts";
const useStyles = makeStyles((theme) => ({
  root: {
    width: "100%",
    maxWidth: 360,
    backgroundColor: theme.palette.background.paper
  }
}));
const ListItem = withStyles({
  root: {
    "&$selected": {
      backgroundColor: "red",
      color: "white",
      "& .MuiListItemIcon-root": {
        color: "white"
      }
    },
    "&$selected:hover": {
      backgroundColor: "purple",
      color: "white",
      "& .MuiListItemIcon-root": {
        color: "white"
      }
    },
    "&:hover": {
      backgroundColor: "blue",
      color: "white",
      "& .MuiListItemIcon-root": {
        color: "white"
      }
    }
  },
  selected: {}
})(MuiListItem);
export default function SelectedListItem() {
  const classes = useStyles();
  const [selectedIndex, setSelectedIndex] = React.useState(1);
  const handleListItemClick = (event, index) => {
    setSelectedIndex(index);
  };
  return (
    <div className={classes.root}>
      <List component="nav" aria-label="main mailbox folders">
        <ListItem
          button
          selected={selectedIndex === 0}
          onClick={(event) => handleListItemClick(event, 0)}
        >
          <ListItemIcon>
            <InboxIcon />
          </ListItemIcon>
          <ListItemText primary="Inbox" />
        </ListItem>
        <ListItem
          button
          selected={selectedIndex === 1}
          onClick={(event) => handleListItemClick(event, 1)}
        >
          <ListItemIcon>
            <DraftsIcon />
          </ListItemIcon>
          <ListItemText primary="Drafts" />
        </ListItem>
      </List>
      <Divider />
      <List component="nav" aria-label="secondary mailbox folder">
        <ListItem
          button
          selected={selectedIndex === 2}
          onClick={(event) => handleListItemClick(event, 2)}
        >
          <ListItemText primary="Trash" />
        </ListItem>
        <ListItem
          button
          selected={selectedIndex === 3}
          onClick={(event) => handleListItemClick(event, 3)}
        >
          <ListItemText primary="Spam" />
        </ListItem>
      </List>
    </div>
  );
}

Edit ListItem selected and hover

Related answers:

Solution 2

You can use the sx prop in MUI v5:

<List
  sx={{
    // selected and (selected + hover) states
    '&& .Mui-selected, && .Mui-selected:hover': {
      bgcolor: 'red',
      '&, & .MuiListItemIcon-root': {
        color: 'pink',
      },
    },
    // hover states
    '& .MuiListItemButton-root:hover': {
      bgcolor: 'orange',
      '&, & .MuiListItemIcon-root': {
        color: 'yellow',
      },
    },
  }}
>

Or styled to create a styled component that can be reused multiple times:

import MuiList from '@mui/material/List';
const List = styled(MuiList)({
  // selected and (selected + hover) states
  '&& .Mui-selected, && .Mui-selected:hover': {
    backgroundColor: 'red',
    '&, & .MuiListItemIcon-root': {
      color: 'pink',
    },
  },
  // hover states
  '& .MuiListItemButton-root:hover': {
    backgroundColor: 'orange',
    '&, & .MuiListItemIcon-root': {
      color: 'yellow',
    },
  },
});

Live Demo

Codesandbox Demo

Share:
16,597

Related videos on Youtube

realtimez
Author by

realtimez

Updated on June 16, 2022

Comments

  • realtimez
    realtimez 11 months

    Can't get 'selected' or 'hover colors to work for ListItem. For selected tried setting its classes like:

    <ListItem selected button key="home" classes={{ selected: classes.listItemSelected }}>
      <ListItemText primary="Hi"/>
    </ListItem>
    

    and then setting the style like:

    const useStyles = makeStyles((theme) => ({
      listItemSelected:{
        backgroundColor: "#ff0000",
      },
    }));
    

    But it doesn't do anything, the 'selected' is described in the ListItem component API here.

    How do you get to set the color of both the selected and hover for ListItem?

  • blah
    blah about 2 years
    How about the ListItemIcon? I noticed that it doesn't change color with the text. How would I go about changing the ListItemIcon color as well?
  • Ryan Cogswell
    Ryan Cogswell about 2 years
    @blah I've updated my example to change the icon color as well.
  • Eric Liprandi
    Eric Liprandi almost 2 years
    @RyanCogswell super useful example. Can you point to an explanation? I had originally missed the selected: {} and it didn't work. Fairly new to React and Mui, but very curious how that works... or where it's documented.
  • Reza
    Reza over 1 year
    The great solution, thanks.
  • thedanotto
    thedanotto over 1 year
    "&:hover": oh duh, so obvious.... /s thanks for the tip

Related