Using Props to Set '&:Hover' Background-Color

Using props to set '&:hover' background-color

You can achieve this by creating your own custom chip component. In order to be able to use props to control the styling, you can use the makeStyles. The makeStyles function returns a hook that can accept an object parameter for providing variables to your styles.

Here's a possible CustomChip implementaton:

import React from "react";
import Chip from "@material-ui/core/Chip";
import { makeStyles } from "@material-ui/core/styles";
import { emphasize } from "@material-ui/core/styles/colorManipulator";

const useChipStyles = makeStyles({
chip: {
color: ({ color }) => color,
backgroundColor: ({ backgroundColor }) => backgroundColor,
"&:hover, &:focus": {
backgroundColor: ({ hoverBackgroundColor, backgroundColor }) =>
hoverBackgroundColor
? hoverBackgroundColor
: emphasize(backgroundColor, 0.08)
},
"&:active": {
backgroundColor: ({ hoverBackgroundColor, backgroundColor }) =>
emphasize(
hoverBackgroundColor ? hoverBackgroundColor : backgroundColor,
0.12
)
}
}
});
const CustomChip = ({
color,
backgroundColor,
hoverBackgroundColor,
...rest
}) => {
const classes = useChipStyles({
color,
backgroundColor,
hoverBackgroundColor
});
return <Chip className={classes.chip} {...rest} />;
};
export default CustomChip;

The styling approach (including the use of the emphasize function to generate the hover and active colors) is based on the approach used internally for Chip.

This can then be used like this:

      <CustomChip
label="Custom Chip 1"
color="green"
backgroundColor="#ccf"
onClick={() => {
console.log("clicked 1");
}}
/>
<CustomChip
label="Custom Chip 2"
color="#f0f"
backgroundColor="#fcc"
hoverBackgroundColor="#afa"
onClick={() => {
console.log("clicked 2");
}}
/>

Here's a CodeSandbox demonstrating this:

Edit Chip color (forked)


Here's a Material-UI v5 version of the example:

import Chip from "@material-ui/core/Chip";
import { styled } from "@material-ui/core/styles";
import { emphasize } from "@material-ui/core/styles";
import { shouldForwardProp } from "@material-ui/system";
function customShouldForwardProp(prop) {
return (
prop !== "color" &&
prop !== "backgroundColor" &&
prop !== "hoverBackgroundColor" &&
shouldForwardProp(prop)
);
}
const CustomChip = styled(Chip, { shouldForwardProp: customShouldForwardProp })(
({ color, backgroundColor, hoverBackgroundColor }) => ({
color: color,
backgroundColor: backgroundColor,
"&:hover, &:focus": {
backgroundColor: hoverBackgroundColor
? hoverBackgroundColor
: emphasize(backgroundColor, 0.08)
},
"&:active": {
backgroundColor: emphasize(
hoverBackgroundColor ? hoverBackgroundColor : backgroundColor,
0.12
)
}
})
);

export default CustomChip;

Edit Chip color

MaterialUI Custom Hover Style

You should define a key for TableRow as a className and then put your hover style right on that class name as an object.

const styles = theme => ({
...
tr: {
background: "#f1f1f1",
'&:hover': {
background: "#f00",
},
},
...
});

return <TableRow className={props.classes.tr} ...>

In another example it would be something like this:

const styles = {
tr: {
background: "#f1f1f1",
'&:hover': {
background: "#f00",
}
}
};

function Table(props) {
return (
<Table>
<TableRow className={props.classes.tr}>
{"table row"}
</TableRow>
</Table>
);
}

export default withStyles(styles)(Table);

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

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:

  • How to overried the selected classes in menuItem in material ui REACTjs?
  • How to change the styles of ListItem element with the "onclick" event?

React JSX - Setting a dynamic :hover color pseudoclass property

First, when you are using a declarative library such as React, you shouldn't communicate directly with the DOM. Instead you should declare how the DOM should look like given certain state. Later on you change the state to achieve the UI effect you want.

To change the state when the user moves in and out, you can use onMouseEnter and onMouseLeave.

The code should be something like

function App({color}) {
const [isFocused, setFocus] = useState(false);

return (
<Link
href="https://stackoverflow.com"
onMouseEnter={() => setFocus(true)}
onMouseLeave={() => setFocus(false)}
className="hoverColor"
style={{
backgroundColor: isFocused ? color : ""
}}
>
Style via React
</Link>
);
}

You can see that you tell react what do you want to do (set backgroundColor red) for a certain state (isFocused is true) so to manipulate the DOM you should call setFocus.

That said, I really recommend to use css solutions when it's possible. In this case you can easily achieve the hover / focus effect using css by using variables to pass the color from React to the css.

<Link
style={{ "--background-color": color }}
href="https://stackoverflow.com"
className="link-hover"
>
Style via Css
</Link>
.link-hover:hover {
background-color: var(--background-color);
}

Demo with both of the ways: https://codesandbox.io/s/pensive-sun-m9jv2s?file=/src/App.js

(I simulated the Link component for the demo, yours probably looks a bit different.)

MUI Button hover background color and text color

You probably don't want to change the button's :active state but the default and the :hover state. The following sets the button color to #fff and the backgroundColor to #3c52b2 and switch them on :hover.

I'm not sure how you applied the updated styles (or how you tried to override the default styles), I created this snippet below with makeStyles() but the idea is the same with the withStyles() HOC.



const { 
AppBar,
Button,
makeStyles,
Toolbar,
Typography,
} = MaterialUI

const useStyles = makeStyles({
flexGrow: {
flex: '1',
},
button: {
backgroundColor: '#3c52b2',
color: '#fff',
'&:hover': {
backgroundColor: '#fff',
color: '#3c52b2',
},
}})

function AppBarWithButtons() {
const classes = useStyles()

return (
<AppBar>
<Toolbar>
<Typography>
YourApp
</Typography>
<div className={classes.flexGrow} />
<Button className={classes.button}>
Button 1
</Button>
<Button className={classes.button}>
Button 2
</Button>
</Toolbar>
</AppBar>
);
};

ReactDOM.render(
<React.StrictMode>
<AppBarWithButtons />
</React.StrictMode>,
document.getElementById("root")
)
<div id="root"></div>
<script src="https://unpkg.com/react/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@material-ui/core@latest/umd/material-ui.production.min.js"></script>

How to change the dropdown hover color react Material-UI Select

The container of the menu list is a Paper which is part of the Menu (the dropdown of the Select). You can target the props of the nested component like below. See here for the list of Menu classNames. Also have a look at all classNames for the component states.

<Select
// to override the border color of the Select input
sx={{
"&:hover": {
"&& fieldset": {
border: "3px solid green"
}
}
}}
// to override the color of the dropdown container
MenuProps={{
PaperProps: {
sx: {
"& .MuiMenuItem-root.Mui-selected": {
backgroundColor: "yellow"
},
"& .MuiMenuItem-root:hover": {
backgroundColor: "pink"
},
"& .MuiMenuItem-root.Mui-selected:hover": {
backgroundColor: "red"
}
}
}
}}

Live Demo

Codesandbox Demo

Inline CSS styles in React: how to implement a:hover?

I'm in the same situation. Really like the pattern of keeping the styling in the components but the hover states seems like the last hurdle.

What I did was writing a mixin that you can add to your component that needs hover states.
This mixin will add a new hovered property to the state of your component. It will be set to true if the user hovers over the main DOM node of the component and sets it back to false if the users leaves the element.

Now in your component render function you can do something like:

<button style={m(
this.styles.container,
this.state.hovered && this.styles.hover,
)}>{this.props.children}</button>

Now each time the state of the hovered state changes the component will rerender.

I've also create a sandbox repo for this that I use to test some of these patterns myself. Check it out if you want to see an example of my implementation.

https://github.com/Sitebase/cssinjs/tree/feature-interaction-mixin

How do you change a style of a child when hovering over a parent using MUI styles?

Below is an example of the correct syntax for v4 ("& $addIcon" nested within &:hover). Further down are some v5 examples.

import * as React from "react";
import { render } from "react-dom";
import { Grid, makeStyles } from "@material-ui/core";
import AddIcon from "@material-ui/icons/Add";

const useStyles = makeStyles(theme => ({
outerDiv: {
backgroundColor: theme.palette.grey[200],
padding: theme.spacing(4),
'&:hover': {
cursor: 'pointer',
backgroundColor: theme.palette.grey[100],
"& $addIcon": {
color: "purple"
}
}
},
addIcon: (props: { dragActive: boolean }) => ({
height: 50,
width: 50,
color: theme.palette.grey[400],
marginBottom: theme.spacing(2)
})
}));

function App() {
const classes = useStyles();
return (
<Grid container>
<Grid item className={classes.outerDiv}>
<AddIcon className={classes.addIcon} />
</Grid>
</Grid>
);
}

const rootElement = document.getElementById("root");
render(<App />, rootElement);

Edit eager-tesla-xw2cg

Related documentation and answers:

  • https://cssinjs.org/jss-plugin-nested?v=v10.0.0#use-rulename-to-reference-a-local-rule-within-the-same-style-sheet
  • how to use css in JS for nested hover styles, Material UI
  • Material UI: affect children based on class
  • Advanced styling in material-ui

For those who have started using Material-UI v5, the example below implements the same styles but leveraging the new sx prop.

import Grid from "@mui/material/Grid";
import { useTheme } from "@mui/material/styles";
import AddIcon from "@mui/icons-material/Add";

export default function App() {
const theme = useTheme();
return (
<Grid container>
<Grid
item
sx={{
p: 4,
backgroundColor: theme.palette.grey[200],
"&:hover": {
backgroundColor: theme.palette.grey[100],
cursor: "pointer",
"& .addIcon": {
color: "purple"
}
}
}}
>
<AddIcon
className="addIcon"
sx={{
height: "50px",
width: "50px",
color: theme.palette.grey[400],
mb: 2
}}
/>
</Grid>
</Grid>
);
}

Edit hover over parent


Here's another v5 example, but using Emotion's styled function rather than Material-UI's sx prop:

import Grid from "@mui/material/Grid";
import { createTheme, ThemeProvider } from "@mui/material/styles";
import AddIcon from "@mui/icons-material/Add";
import styled from "@emotion/styled/macro";

const StyledAddIcon = styled(AddIcon)(({ theme }) => ({
height: "50px",
width: "50px",
color: theme.palette.grey[400],
marginBottom: theme.spacing(2)
}));
const StyledGrid = styled(Grid)(({ theme }) => ({
padding: theme.spacing(4),
backgroundColor: theme.palette.grey[200],
"&:hover": {
backgroundColor: theme.palette.grey[100],
cursor: "pointer",
[`${StyledAddIcon}`]: {
color: "purple"
}
}
}));
const theme = createTheme();
export default function App() {
return (
<ThemeProvider theme={theme}>
<Grid container>
<StyledGrid item>
<StyledAddIcon />
</StyledGrid>
</Grid>
</ThemeProvider>
);
}

Edit hover over parent


And one more v5 example using Emotion's css prop:

/** @jsxImportSource @emotion/react */
import Grid from "@mui/material/Grid";
import { createTheme, ThemeProvider } from "@mui/material/styles";
import AddIcon from "@mui/icons-material/Add";

const theme = createTheme();
export default function App() {
return (
<ThemeProvider theme={theme}>
<Grid container>
<Grid
item
css={(theme) => ({
padding: theme.spacing(4),
backgroundColor: theme.palette.grey[200],
"&:hover": {
backgroundColor: theme.palette.grey[100],
cursor: "pointer",
"& .addIcon": {
color: "purple"
}
}
})}
>
<AddIcon
className="addIcon"
css={(theme) => ({
height: "50px",
width: "50px",
color: theme.palette.grey[400],
marginBottom: theme.spacing(2)
})}
/>
</Grid>
</Grid>
</ThemeProvider>
);
}

Edit hover over parent



Related Topics



Leave a reply



Submit