13

I just want to know if there is a way to use framer-motion with Material-Ui. I tried but I am not getting it.

Satyam
  • 567
  • 1
  • 6
  • 20

5 Answers5

56

Material-UI has component prop option for this kind of requirement and should do better and more elegant approach than the wrapping-approach. Then, you can pass any props provided by framer-motion package to your Material-UI component as long as they're not conflicted (i'm not sure if any).

 <Button
  color="inherit"
  variant='contained'
  size="large"
  component={motion.div}
  whileHover={{
    scale: 1.2,
    transition: { duration: 0.3 }
  }}
  whileTap={{ scale: 0.9 }}
>
  Button
</Button>
5

Your question made me curious. I never tried the framer-motion, but was planning to learn it recently.

So I gave it a try, created a sandbox, added a Material UI and framer motion packages in it.

Just created a small button in the middle of the page using Material UI. And wrapped the button using <motion.div> tag, like this:

import React from "react";
import { motion } from "framer-motion";
import Button from "@material-ui/core/Button";

function AnimatableDiv() {
  return (
    <motion.div
      className="animatable"
      whileHover={{
        scale: 1.2,
        transition: { duration: 0.3 }
      }}
      whileTap={{ scale: 0.9 }}
    >
      <Button size="large" className="animatable">
        Button
      </Button>
    </motion.div>
  );
}

export default AnimatableDiv;

And it worked!

You might be thinking what if I use the the motion. directly on the <Button> component, like this:

<motion.Button size="large" className="animatable">
  Button
</motion.Button>

Well, I did think of this, and I applied it as well and all the styling that Material UI applied to that button were lost! So do not follow this approach! I repeat do not!

Here's the link can have a look at it: https://codesandbox.io/s/brave-sutherland-5bki9

Prathamesh Koshti
  • 1,322
  • 10
  • 17
4

I was also in the same situation, so after a small research, and some trial and error I wrote a small article on this, hope you guys get helped from this, and if any suggestion feels free to elaborate in the comment section.

https://aishmn.medium.com/how-to-use-material-ui-and-framer-motion-together-6026fed96a4c

2

The accepted answer's strategy is the easiest way to implement this but another strategy is to use framer-motion's wrapping.

This is my implementation with Typescript for those who might search for this problem.

Box.tsx

import React from "react";
import { motion } from "framer-motion";

import MuiBox, { BoxProps } from "@mui/material/Box";

const BoxComponent = React.forwardRef((props: BoxProps, ref) => (
  <MuiBox {...props} ref={ref} />
));

const Box = motion(BoxComponent);

export default Box;

Then use it in your component

import Box from "./Box";

// The motion-wrapped Mui Box now also accepts framer-motion's props
<Box
  initial={{ opacity: 0 }}
  animate={{ x: 100, rotate: [null, 10, 20], opacity: 1 }}
  whileHover={{ scale: [null, 1.5, 1.4] }}
  width={100}
  height={100}
  border="1px solid red"
/>
Tom
  • 107
  • 7
  • This works best with Nextjs because `component={motion.div}` throws a hydration error in Nextjs – Ilir Feb 02 '23 at 10:33
  • This look like the best approach and also recommended by framer-motion doc (https://www.framer.com/motion/component/#custom-components), currently. Mine was almost 2 years ago and might be out-dated (or may be used as work-around for quick fix or basic requirements) due to the fact that things are changing frequently in this eco-system. – Ramazan Çağrı AKAR Feb 23 '23 at 05:59
0

I had the same question so i digged a little bit in the motion doc. and i found this: Any component can be turned into a motion component by wrapping it with the motion() function. So i did this:

    import { TextField } from "@mui/material";
    import { motion } from "framer-motion";

    export default function YourComponent() {
    const TextFieldMotion = motion(TextField);
    return (
            <TextFieldMotion 
            animate={{ x: [0,20] }} 
            transition = {{ ease: "easeInOut", duration: 3 }} 
            variant="filled" 
            label="first name" 
            />
    )
     };

for more information: https://www.framer.com/docs/component/