Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I'm using MUI in react. Let's say I have this component with these styles:

const useStyles = makeStyles(theme => ({   outerDiv: {     backgroundColor: theme.palette.grey[200],     padding: theme.spacing(4),     '&:hover': {       cursor: 'pointer',       backgroundColor: theme.palette.grey[100]    }   },   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>   ); } 

I want to change the style of addIcon when hovering over outerDiv using the styles above.

Here's my example.

like image 377
Pieter Buys Avatar asked Dec 04 '19 14:12

Pieter Buys


People also ask

How do you style the parent element when hovering a child element?

The trick is to give the sibling the same size and position as the parent and to style the sibling instead of the parent. This will look like the parent is styled!

How do you override MUI component style?

If you want to override a component's styles using custom classes, you can use the className prop, available on each component.

How to add hover effect in Material UI?

The hover selector is simple to add. There is no space needed because it it selecting the hover pseudo-class applied at the top level of the button component. Notice that there is no comma or semicolon between the &:hover and &:focus selectors. Instead of working with Material-UI's styling API, it overrides it.

How do you add a hover style in react?

Set the onMouseEnter and onMouseLeave props on the element. When the user hovers over or out of the element, update a state variable. Conditionally set inline styles on the element.


2 Answers

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

like image 94
Ryan Cogswell Avatar answered Sep 17 '22 14:09

Ryan Cogswell


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>   ) } 
like image 34
James Hooper Avatar answered Sep 19 '22 14:09

James Hooper