Oleksandr Danylchenko
Oleksandr Danylchenko

Reputation: 697

Override the transition delay in React Framer Motion

I created motion.div component, which contains initial, animate and whileTap properties:

<motion.button
  initial={'initial'}
  animate={'in'}
  whileTap={'onTap'}
  variants={introButtonVariants}
>...</>

in variation contains transition with the delay: 0.5:

in: {
  x: 0,
  scale: 1,
  transition: { duration: 0.5, delay: 0.5 }
}

But this delay: 0.5 is affecting onTap variation, even if I explicitly specify new delay there. So on tap, it instantly goes in the "tapped" mode but then it stops for 0.5s. before backward animation.

onTap: {
  scale: 0.8,
  transition: { scale: { delay: 0 } }
}

How can the delay value, which goes to animate property, be overridden by the new one, which is defined in the new variation?

Upvotes: 3

Views: 4994

Answers (2)

Qwilliams815
Qwilliams815

Reputation: 21

Fast forward 3 years and framer-motion v3 appears to have broken this again so here is my current fix as of v3.30.

If I understand your question correctly, it seems like you are trying to override the button's animation delay after it initially loads so that all subsequent hover and tap gestures have 0 delay.

My workaround is to store the delay value in state and update it after the initial animation is complete utilizing framer-motion's onAnimationComplete callback.

Here is a similar copypaste and a codesandbox demo running framer-motion ^3.30 that I made for this user's question:

import React, { useState } from "react";
import { motion } from "framer-motion";
import "./styles.css";

const size = 200;
const radius = 40;
const color = "#0CF";

export default function App() {
  const [delay, setDelay] = useState(2); // Initial value

  const variants = {
    start: { scale: 0 },
    active: { scale: 1.25, transition: { delay: delay } },
    hovering: {
      scale: 5,
      transition: { delay: delay },
    },
  };

  return (
    <div className="App">
      <motion.div
        style={{
          width: size,
          height: size,
          backgroundColor: color,
          borderRadius: radius,
        }}
        variants={variants}
        initial="start"
        animate={"active"}
        whileHover={"hovering"}
        transition={{}}
        onAnimationComplete={() => setDelay(0)} // Subsequent value
      />
    </div>
  );
}

Upvotes: 2

pumasky2
pumasky2

Reputation: 46

Was faced with the same problem and found an answer in official discord. Looks like at this moment it's only possible with spread operator to reset delay in animate state.

Here is a working example: https://codesandbox.io/s/motion-transition-70yhg?file=/src/App.js

Copypaste:

const size = 200;
const radius = 40;
const color = "#0CF";
const curve = {
    type: "spring",
    stiffness: 400,
    damping: 30
};

export default function App() {
    const variants = {
        active: { scale: 1.25, transition: { ...curve, delay: 2 } },
        hovering: {
            scale: 1.5,
            rotate: 180,
            transition: { ...curve, delay: 0 }
        }
    };

    return (
        <div className="App">
            <motion.div
                style={{
                    width: size,
                    height: size,
                    backgroundColor: color,
                    borderRadius: radius
                }}
                variants={variants}
                animate={"active"}
                whileHover={"hovering"}
                transition={{ ...curve }}
            />
        </div>
    );
}

Upvotes: 3

Related Questions