How do you change a style of a child when hovering over a parent using material-ui jss 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);
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> );}
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> );}
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> );}
Possibly an obvious point, but just to add to the answer above: if you are referencing a separate className, don't forget that you also need to create it in the makeStyles hook or else it won't work. For instance:
const useStyles = makeStyles({ parent: { color: "red", "&:hover": { "& $child": { color: "blue" // will only apply if the class below is declared (can be declared empty) } } }, // child: {} // THIS must be created / uncommented in order for the code above to work; assigning the className to the component alone won't work.})const Example = () => { const classes = useStyles() return ( <Box className={classes.parent}> <Box className={classes.child}> I am red unless you create the child class in the hook </Box> </Box> )}