Vencovsky
Vencovsky

Reputation: 31625

How can I use two transitions with material ui?

What I'm trying to do is use Fade and Slide in the same component.

<Slide in={isValid} timeout={timeout} direction="left">                                
    <Fade in={isValid} timeout={timeout}>
        <Foo />
    </Fade>
</Slide>

But it doesn't work.

When isValid is true, it slides the component without the fade effect and when it's false, the component just blinks and disappears.

How can I make it work? I don't want to use makeStyle.

Upvotes: 9

Views: 8009

Answers (2)

Ryan Cogswell
Ryan Cogswell

Reputation: 81026

The Slide and the Fade components both change the style.transition property, so if they act on the same element they clobber portions of the other's work.

The way to get this to work is for them to act on different elements. Introducing a div between the two transitions gets the desired behavior.

import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import Switch from "@material-ui/core/Switch";
import Paper from "@material-ui/core/Paper";
import Fade from "@material-ui/core/Fade";
import Slide from "@material-ui/core/Slide";
import FormControlLabel from "@material-ui/core/FormControlLabel";

const useStyles = makeStyles(theme => ({
  root: {
    height: 180
  },
  container: {
    display: "flex"
  },
  paper: {
    margin: theme.spacing(1),
    backgroundColor: "lightblue"
  },
  svg: {
    width: 100,
    height: 100
  },
  polygon: {
    fill: theme.palette.primary.main,
    stroke: theme.palette.divider,
    strokeWidth: 1
  }
}));

export default function SlideAndFade() {
  const classes = useStyles();
  const [checked, setChecked] = React.useState(false);

  const handleChange = () => {
    setChecked(prev => !prev);
  };

  return (
    <div className={classes.root}>
      <FormControlLabel
        control={<Switch checked={checked} onChange={handleChange} />}
        label="Show"
      />
      <div className={classes.container}>
        <Slide in={checked} timeout={1000}>
          <div>
            <Fade in={checked} timeout={1000}>
              <Paper elevation={4} className={classes.paper}>
                <svg className={classes.svg}>
                  <polygon
                    points="0,100 50,00, 100,100"
                    className={classes.polygon}
                  />
                </svg>
              </Paper>
            </Fade>
          </div>
        </Slide>
      </div>
    </div>
  );
}

Edit Material demo

Upvotes: 9

Vencovsky
Vencovsky

Reputation: 31625

I realized that if you wrap the transition in a div or other element to make it as a container, it will work.

<Slide in={isValid} timeout={timeout} direction="left">        
    <div> // adding this div will make it work                       
        <Fade in={isValid} timeout={timeout}>
            <Foo />
        </Fade>
    </div>
</Slide>

And then you can just create your own Fade component that wraps a div.

const MyFade = React.forwardRef(
  ({ children, in: In, timeout, ...otherProps }, ref) => {
    return (
      <div ref={ref} {...otherProps}>
        <Fade in={In} timeout={timeout}>
          {children}
        </Fade>
      </div>
    );
  }
);

Thanks to @Ryan Cogswe that also helped in this.

Upvotes: 4

Related Questions