Toggle animation
Warning: These pages are from before the launch of Framer X22 and are about the older animation API. These animations might still work in the current version of Framer but are officially deprecated. Learn about the current animation API here.
We want an animation that goes back and forth between two different states.
One of Framer’s example overrides (in Examples.tsx
) actually does this.
It’s a set of two overrides. You attach FlipOutput
to the frame you want to flip, and with the other one, FlipInput
, you start the animation.
export const FlipOutput: Override = () => {
return {
rotationY: data.rotationY
};
};
export const FlipInput: Override = () => {
return {
onTap() {
const toggle = data.toggle;
animate.spring(
{ rotationY: data.rotationY },
{
rotationY: toggle ? 360 : 0
},
{ tension: 200, friction: 20 }
);
data.toggle = !toggle;
}
};
};
It contains an extra (Boolean) variable, data.toggle
to keep track of the state of the frame.
The state being: Was the frame rotated (around the y-axis) to 360
degrees, or is it back at the initial 0
degrees?
If you’re wondering why it animates back from 360
to 0
(which actually looks the same). It’s because animating to 360
for a second time, with the frame already being in that position, would have no effect.
An ON/OFF button
We’ll also use a Boolean variable in which we save the ‘ON’ or ‘OFF’ state of our button.
Here I used toggle
; initially it’s true
, so that will stand for ‘ON’.
const data = Data({
color: Animatable("green"),
toggle: true
});
The Animatable
is for the button’s "green"
color.
In the override function, I create a variable, animateToColor
, in which I can save the color to animate to. It’s a let
because I’ll need to change it.
Then, with an if…else statement, I check whether data.toggle
is true
.
When it is, I set animateToColor
to "red"
, and when not, I set it back to "green"
.
export const Button: Override = () => {
return {
background: data.color,
onTap() {
let animateToColor = "";
if (data.toggle) {
animateToColor = "red";
} else {
animateToColor = "green";
}
animate(data.color, animateToColor);
data.toggle = !data.toggle;
}
};
};
I then animate
to the correct color.
And I set data.toggle
to its inverse value by typing a !
before it. (If it was true
then it will be false
, and also the other way round.)
But actually, this can be shorter, like this:
export const Button: Override = () => {
return {
background: data.color,
onTap() {
const animateToColor = data.toggle ? "red" : "green";
animate(data.color, animateToColor);
data.toggle = !data.toggle;
}
};
};
It now uses the JavaScript ternary operator, a shorter way of writing an if…else statement.
If data.toggle
is true, then the first value (after ?
) will be used, and if not, the second value (after :
). Just one line instead of the above six lines.
Text on the button
We can add a button label as well. You can’t animate text, so it shouldn’t be an Animatable
but a common string variable.
const data = Data({
color: Animatable("green"),
label: "ON",
toggle: true
});
And I made a separate override that I attached to the text block.
export const ButtonText: Override = () => {
return {
text: data.label
};
};
When the button is tapped, I change the data.label
to either "OFF"
or "ON"
, also in a one-liner.
export const Button: Override = () => {
return {
background: data.color,
onTap() {
const animateToColor = data.toggle ? "red" : "green";
animate(data.color, animateToColor);
data.label = data.toggle ? "OFF" : "ON";
data.toggle = !data.toggle;
}
};
};
All together it looks like this:
import { Data, animate, Override, Animatable } from "framer";
const data = Data({
color: Animatable("green"),
label: "ON",
toggle: true
});
export const ButtonText: Override = () => {
return {
text: data.label
};
};
export const Button: Override = () => {
return {
background: data.color,
onTap() {
const animateToColor = data.toggle ? "red" : "green";
animate(data.color, animateToColor);
data.label = data.toggle ? "OFF" : "ON";
data.toggle = !data.toggle;
}
};
};
download this project