I’m building a counter component in a React application using framer-motion for the animation. The counter increments every second, and the animation works perfectly on web browsers like Chrome and Firefox, but sometimes the counter doesn’t even appear on iOS (iPhone) Safari.
Here is my code
import { motion, AnimatePresence } from "framer-motion";
import { useEffect, useState } from "react";
import "./Counter.css";
export const Counter = () => {
const [count, setCount] = useState(0);
const increment = 0.001;
useEffect(() => {
const storedStartTime = localStorage.getItem("startTime");
if (storedStartTime) {
const startTime = new Date(storedStartTime).getTime();
const currentTime = Date.now();
const elapsedSeconds = (currentTime - startTime) / 1000;
setCount(elapsedSeconds * increment);
}
}, []);
useEffect(() => {
const interval = setInterval(() => {
setCount((prevCoins) => prevCoins + increment);
}, 1000);
return () => clearInterval(interval);
}, []);
const digitVariants = {
enter: {
y: "100%",
scale: 0.8,
opacity: 0,
transition: { duration: 0.2, ease: "easeInOut" },
},
center: {
y: "0%",
scale: 1,
opacity: 1,
transition: { duration: 0.2, ease: "easeInOut" },
},
exit: {
y: "-100%",
scale: 0.8,
opacity: 0,
transition: { duration: 0.2, ease: "easeInOut" },
},
};
const getDigits = (value: number) => value.toFixed(3).split("");
const digits = getDigits(count);
const prevDigits = getDigits(count - increment);
return (
<div className="counter-container">
{digits.map((digit, index) => {
const prevDigit = prevDigits[index];
const shouldAnimate = digit !== prevDigit;
return (
<div key={index} className="counter">
<AnimatePresence>
{shouldAnimate && (
<motion.div
key={`prev-${index}-${prevDigit}`}
initial="center"
animate="exit"
exit="exit"
variants={digitVariants}
className="timer-current-digit"
>
{prevDigit}
</motion.div>
)}
<motion.div
key={`digit-${index}-${digit}`}
initial="enter"
animate="center"
exit="exit"
variants={digitVariants}
className="timer-digit"
>
{digit}
</motion.div>
</AnimatePresence>
</div>
);
})}
</div>
);
};
CSS
.counter-container {
display: flex;
height: 16px;
font-size: 16px;
font-weight: 700;
line-height: 16px;
align-items: flex-start;
}
.counter {
position: relative;
height: 16px;
width: 10px;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.timer-digit {
position: absolute;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.counter-container,
.counter,
.timer-digit {
transform: translateZ(0);
-webkit-transform: translateZ(0);
will-change: transform, opacity;
}
I suspect it might be related to the setInterval updates or how framer-motion animations are handled in Safari on iOS, but I’m not sure. I’ve checked that animations are applied as expected on desktop browsers, but they sometimes don’t render at all on iPhone.
What would be the best way to fix this so the animation works reliably on iOS devices?