aarona
aarona

Reputation: 37344

Can I inherit styles when using createStyles?

Here is a createStyles statement in my Typescript code:

const useStyles = makeStyles((theme: Theme) =>
  createStyles({
    menuOpen: {
      zIndex: 1,
      width: 200,
      height: '100%',
      position: 'fixed',
      top: 48,
      transition: 'left .1s',
      marginRight: theme.spacing(2),
      left: 0,
      background: '#3f51b5',
      '& div:first-element': {
        marginTop: 100
      }
    },
    menuClose: {
      zIndex: 1,
      width: 200,
      height: '100%',
      position: 'fixed',
      top: 48,
      transition: 'left .1s',
      marginRight: theme.spacing(2),
      left: -200,
      background: '#3f51b5',
      '& div:first-element': {
        marginTop: 100
      }
    },
  }),
);

I'm flipping between these to open or close a menu (using a useState variable). As you can see, these styles share common attributes. How would I be able to make a menu style that these two styles could inherit from?

Edit: So it looks like the transitioning stuff isn't working and I'm wondering if thats because React reload those DOM elements? I tried adding the transitions in the menuClose and menuOpen styles just in case it needed them but the menu acts like it doesnt have a transition attribute.

After @doglozano's answer I have the following in my createStyles function:

// I've even tried putting the transition in a div wrapper
// but I think that element is getting overwritten also.
toolBar: {
  '& div': {
    transition: 'left .1s'
  }
},
menu: {
  zIndex: 1,
  width: 200,
  height: '100%',
  position: 'fixed',
  top: 48,
  transition: 'left .1s',
  marginRight: theme.spacing(2),
  left: -200,
  background: '#3f51b5',
  '& div:first-element': {
    marginTop: 100
  }
},
menuOpen: {
  left: 0,
  transition: 'left .1s',
},
menuClose: {
  left: -200,
  transition: 'left .1s',
},

When my menu is closed:

.makeStyles-menuClose-7 {
    left: -200px;
    transition: left .1s;
}
.makeStyles-menu-5 {
    top: 48px;
    left: -200px;
    width: 200px;
    height: 100%;
    z-index: 1;
    position: fixed;
    background: #3f51b5;
    transition: left .1s;
    margin-right: 16px;
}
.makeStyles-toolBar-4 {
    transition: left .1s;
}

When my menu is open:

.makeStyles-menuOpen-6 {
    left: 0;
    transition: left .1s;
}
.makeStyles-menu-5 {
    top: 48px;
    left: -200px;
    width: 200px;
    height: 100%;
    z-index: 1;
    position: fixed;
    background: #3f51b5;
    transition: left .1s;
    margin-right: 16px;
}
.makeStyles-toolBar-4 {
    transition: left .1s;
}

Edit 2: Here is my Sandbox link.

Any ideas?

Upvotes: 3

Views: 2941

Answers (1)

dglozano
dglozano

Reputation: 6607

You could define a base class with all the common attributes, and then have only the specific attributes in menuOpen and menuClose. Then, you can use a library such as classnames or clsx to apply the base class always, and then conditionally apply also either menuOpen or menuClose based on your state variable.

Would look something like this:


import clsx from 'clsx';

...

const useStyles = makeStyles((theme: Theme) =>
  createStyles({
    menu: {
      zIndex: 1,
      width: 200,
      height: '100%',
      position: 'fixed',
      top: 48,
      transition: 'left .1s',
      marginRight: theme.spacing(2),
      background: '#3f51b5',
      '& div:first-element': {
        marginTop: 100
      }
    }
    menuOpen: {
      left: 0,
    },
    menuClose: {
      left: -200,
    },
  }),
);

...

const YourStyledCommponent = ({ classes }) => {

   const [isOpen, setOpen] = useState(false);

   return (
      <SomeMuiComponent 
         className={clsx(classes.menu, {
            [classes.menuOpen]: isOpen,
            [classes.menuClose]: !isOpen,
         })}
      />
   );
}

Of course you could also say that your base menu style will be the close state, and then you end up having only one additional style:


import clsx from "clsx";

...

const useStyles = makeStyles((theme: Theme) =>
  createStyles({
    menu: {
      zIndex: 1,
      width: 200,
      height: '100%',
      position: 'fixed',
      top: 48,
      transition: 'left .1s',
      marginRight: theme.spacing(2),
      background: '#3f51b5',
      left: -200,
      '& div:first-element': {
        marginTop: 100
      }
    }
    menuOpen: {
      left: 0,
    },
  }),
);

...

const YourStyledCommponent = ({ classes }) => {

   const [isOpen, setOpen] = useState(false);

   return (
      <SomeMuiComponent 
         className={clsx(classes.menu, {
            [classes.menuOpen]: isOpen,
         })}
      />
   );
}

EDIT: as stated by @Ryan Cogswell in the comments, clsx would be the recommended library if you are using Material UI >= v4.0, since it already comes included in it 😁.

Upvotes: 3

Related Questions