While Hover and While Tap
These two are an easy way to add interactivity to a canvas element. With just one line of code, you add an automatic animation between two states.

While Hover
Here’s an override example: You give
an object with the properties you want to animate, just like you did earlier with animate
.
import { Override } from "framer"
export function WhileHover(): Override {
return {
whileHover: { scale: 0.8 },
}
}
The frame shrinks to 80 percent of its size when you hover over
With one line of code, you’ve added two animations:
- one that happens when the pointer is over the frame;
- and a reverse animation that runs when the pointer leaves the frame.
And here’s how you do it in a code component:
export function C01_WhileHover() {
return (
<Frame
whileHover={{ scale: 0.8 }}
/>
)
}
(The {{
double curly braces}}
are there because you’re writing the object directly inline.)
whileHover
Animation helpers, whileHover
While Tap
The second one, whileTap
, works the same, but for tap gestures.
And just like with animate
, you can tweak these animations by adding transition
settings.
export function WhileTap(): Override {
return {
whileTap: { scale: 0.8 },
transition: { duration: 0.5 },
}
}
Here the frame shrinks when you press down, but it will take its sweet little time of half a second. And the same thing happens when you release; the grow animation also has a duration
of 0.5
.
whileTap
Animation helpers, whileTap
Both
Naturally, you can also use
and
at the same time:
export function WhileHover_WhileTap(): Override {
return {
whileHover: { radius: 75 },
whileTap: { backgroundColor: "Gold" },
}
}
Initial
Say I would like the frame to fade in when it first appears. We know how to do that: You just add a standard animate
that changes the opacity
:
export function Fade_In(): Override {
return {
animate: { opacity: 1 },
whileHover: { radius: 75 },
whileTap: { backgroundColor: "Gold" },
}
}
… and then, because the frame should initially be invisible, you change its opacity on the canvas to zero.
But it’s annoying to have to hide frames on the canvas. You might forget they’re even there! There’s a solution, though. With the initial
property, you can define which values the frame should animate from.
export function Initial(): Override {
return {
initial: { opacity: 0 },
animate: { opacity: 1 },
whileHover: { radius: 75 },
whileTap: { backgroundColor: "Gold" },
}
}
(Hit to see that fade-in animation again.)
Including transition settings
You know that you can set a frame’s animation options with transition
. But our frame now has three animations, what if we only want to slow down the animate
animation?
For this, you can include a transition
object directly with the animation:
export function Including_Transition_settings(): Override {
return {
initial: { opacity: 0 },
animate: { opacity: 1, transition: { duration: 1 } },
whileHover: {
backgroundColor: "Gold",
transition: { ease: "easeInOut", yoyo: Infinity },
},
whileTap: { backgroundColor: "Orange" },
}
}
The frame’s fade-in animation will now last 1
second, and the whileHover
is changed to a repeating yoyo
animation with an "easeInOut"
curve.
This kind of included transition settings will override the global settings you might have set on the frame’s transition
property.
Transition, transition
Transition, transition
Initial: false
One more thing about initial
: Setting it to false
will cancel the animate
animation.
export function Initial_false(): Override {
return {
initial: false,
animate: { rotate: 45 },
whileHover: { radius: 75 },
whileTap: { backgroundColor: "Gold" },
}
}
Here, the frame will not rotate
to 45
degrees, it’ll just be displayed already turned, without animation.
Naturally, when you comment out the initial: false
, it will animate :
export function Initial_false(): Override {
return {
// initial: false,
animate: { rotate: 45 },
whileHover: { radius: 75 },
whileTap: { backgroundColor: "Gold" },
}
}
But why would you even use initial: false
? You could instead get rid of that animate
line and just rotate the frame on the canvas.
Further ahead, you’ll see that you need not animate
to fixed, pre-defined values. You can animate to a dynamic value provided by one of the hooks. And with initial: false
, you can then suppress all initial animations, whatever that dynamic value might be. There’s an example of this in The useCycle() Hook.
6 comments on “While Hover and While Tap”
Leave a Reply
You must be logged in to post a comment.
How do you switch between two different variants within the “animate:” property?
By making the value you pass to
animate
dynamic.Here’s an example where it changes depending on another Frame being dragged or not:
Or you pass the
animate
property the variable that’s provide by auseState()
hook (animate: state
), so you can dynamically change it to a different variant label, e.g.setState("variantLabel")
Or you give
animate
the AnimationControls object provided by anuseAnimation()
hook, so you can usestart()
. E.g.,animation.start("variantLabel")
Hi Tes, Hmm… when switching between the two variants based on logic, there is no animation triggered. Would this be solved with the animation.start option you mention above? If so, Could you give an example of that?
Hard to tell what might be off without seeing your code, of course.
About
start()
: Check theuseAnimation()
page for more about the AnimationControls object (and itsstart()
function).But that page hasn’t any examples with variants, so I’ll add one here:
This a variants version of the first example on that page. Actually just a recreation of
whileHover
with theonHoverStart()
andonHoverEnd()
events.Can you use onTap in one override to trigger a sequence in another override? Say to tap a card a fade something up from 0 to 1 and back down to 0?
Not 100% sure what you mean, because you’re asking this on this
whileHover
andwhileTap
page. You might mean something like this:… which is like a
whileTap
, but then from one Frame sent to another.But you probably mean something like this:
Here the
onTap()
on one Frame starts a Keyframe animation on another Frame. (AndappState.tapped
is then reset tofalse
a minute after that, so that you can trigger the animation again.)Instead of the resetting with a
setTimeout()
could also use anuseAnimation()
hook to drive the animation, but it’s kind of a hack to share anuseAnimation()
through the Data object. (But it’s possible, here’s an example.)