Archive » Overrides (pre X22)

Overrides (pre X22)

This page is from before the launch of Framer X22 and explains Overrides using the older, now deprecated, animations. There’s an updated explanation of Overrides here.

Overrides (sometimes called code overrides) are a way to quickly make elements on your canvas interactive. With Overrides you can animate Frames and Components and also have them react to events like a tap, hover, drag, etc.

Applying an override

Open ‘Code’ in the Properties Panel to add an override to a (selected) frame.

In the Code tab you then pick which ‘File’ you want to use (there will be one with ‘Examples’), and also the exact ‘Override’ function inside that file.

Override files

From the same menu in the Code tab, you can open the existing ‘Example.tsx’ file in VS Code.

Selecting ‘New File…’ will create a new ‘App.tsx’ file which also contains an example override.

You can add more files if you want, and each file can contain many overrides. But you can only apply one override at a time to a frame.

What are you ‘overriding’?

With an override, you can dynamically change the properties of a Frame or Component. Any property that you can set in the Properties Panel can be changed (or sometimes animated) on the fly.

So you can change a frame’s size and position, but also its fill, border, shadow, etc.

This overriding happens between the Canvas and the Preview. Which means that the result of an override will only be visible in the Preview window.

As a simple example, here’s one that just changes the color of a frame:

export const ChangeColor: Override = () => {
  return {
    background: "red"
  };
};
On the Canvas
In the Preview window

download the example project

Whatever the frame’s Fill was on the Canvas (could be a color, gradient or image) will be overridden. The Frame will simply be red.

You’re overriding the Frame’s styling, its CSS properties, but you can also have it listen to events.

Events

By attaching an event to a frame, you can have it react to, for instance, a tap.

The Framer docs have an example of an override that just listens to an event. It doesn’t change anything on the frame itself, it just writes “Hello” to the Console.

import { Override } from "framer"; ​
 
export function LogTap(): Override {
    return {
        onTap: () => {
            console.log("Hello")
        },
    }
}
download this project

To see the Console, select Inspect ⌘I from the hamburger menu on the Preview window. Or you can also right-click in the preview window and choose ‘Inspect Element.’

The Console is one of the tabs in the Web Inspector that will appear.

When you now tap the frame a “Hello” message will appear in the Console.

And now you also know that whenever you want to find out what’s happening inside an Override that you can log values to the Console.

To see a frame’s current properties (props), for instance, you can do:

export const logProperties: Override = props => {
  return {
    onTap() {
      console.log(props);
    }
  };
};

The example ‘Scale’ override

When selecting ‘New File…’ (from the ‘File’ menu) in the ‘Code’ tab, you’ll get a fresh App.tsx file, with only one simple example override.

The override is named Scale, and when you attach it to a frame, it will scale up with a bounce upon tapping it.

Here’s the code:

import { Data, animate, Override, Animatable } from "framer"

const data = Data({ scale: Animatable(1) })

export const Scale: Override = () => {
  return {
    scale: data.scale,
    onTap() {
      data.scale.set(0.6)
      animate.spring(data.scale, 1)
    },
  }
}
download this project

What is happening here? A lot.

This override…

  • animates the scale property of the frame,
  • but not directly. It actually animates an Animatable value (also called scale) that is saved in an instance of Framer’s Data object.
  • The animation happens when the frame is tapped, it gets triggered by an onTap() event.
  • But because the animation is to the actual scale of the frame (1), the frame is first shrunk to 60% of its size (0.6), so that it can grow again.

Anyway, to make everything a bit more understandable, we’ll take another look at the very simple override mentioned above, and then expand on it to create more complicated overrides.

The simplest possible Override

The ChangeColor override below just changes the background of the frame you attach it to. That’s all, no animation, there’s not even a tap needed to trigger it.

On the Canvas
In the Preview window

It’s the plainest possible override function.

import { Override } from "framer";

export const ChangeColor: Override = () => {
  return {
    background: "red"
  };
};
download the example project

Here’s what’s happening.

  • First, we import Override from the Framer Library.
  • Then we create an ES6 Arrow function (=>),
  • that we save in a const variable with the name of ChangeColor,
  • while giving it the (TypeScript) type of Override.
  • Our function returns a JavaScript object which contains only one key-value pair: the key is background with a value of "red".
  • Ah, and we make sure to export our function.

Okay, step by step, in more detail.

Importing another JavaScript file

import { Override } from "framer";

We import Override from the Framer library so that we can create an override function. That’s also all we need from that library, for now.

Importing is like the script src statement you would use to add a JavaScript library to your webpage, like, e.g., the jQuery library.

<script src="js/jquery-3.3.1.min.js"></script>

An ES6 Arrow function

In JavaScript, you can write functions, like, e.g., an add function, this way:

function add(number1, number2) {
  return number1 + number2
}

This is called a function declaration.

The add function above takes two numbers and returns their sum. You would use it like this:

add(4,5);

You can try it in a Codepen here.

When you type the above line (at the bottom of that Codepen, in its Console), the function will return:

> 9

But can also write functions like this, in what they call a function expression:

add = function(number1, number2) {
  return number1 + number2
}

Note how the name, add, and the function keyword switched place.

But we’ll use an Arrow (=>) function, something new in ES6, which—with this same add example—looks like this:

add = (number1, number2) => {
  return number1 + number2
}

(ES6 refers to version 6 of the ECMA Script programming language. ECMA Script is the official name for JavaScript, and version 6 was finalized in June 2015. You might also see it being referred to as ‘ECMAScript 2015’)

And when the Arrow function doesn’t need any input values, like our ChangeColor example, you can leave the parentheses empty.

TheAnswer = () => {
  return 42;
}

(Try this example on Codepen.)

By the way, when you call the function, you do have to write the parentheses.

TheAnswer();

> 42

Back to our ChangeColor function:

ChangeColor = () => {
  return {
    background: "red"
  };
};

And what does our function do? It return‘s the properties that should be changed on the frame.

Our function returns an object

The updated properties are returned as a JavaScript object.

{
  background: "red"
}

This means that you can set several properties at once. You could, for instance, also change the rotation of the frame:

ChangeColor = () => {
  return {
    background: "red",
    rotation: 45
  };
};

Our function is saved in a const

Our ChangeColor variable, which contains the function, is a const. This stands for ‘constant,’ a variable that cannot be changed afterward.

const ChangeColor = () => {
  return {
    background: "red"
  };
};

The other option in ES6 is let, and those variables can be changed.

let is like the new version of what used to be var in old school JavaScript, a variable that can be changed afterward.

It’s always better to use const, though, because if you then (accidentally) try to use the same variable name for something else, VS Code will warn you.

Here I try to save a text string in our ChangeColor variable:

ChangeColor = "A text string, for example.";

Which results in VS Code putting a squiggly red line under the variable to signal an error.

Hovering over the error brings up more information. Here: “Cannot assign to ‘ChangeColor’ because it is a constant.” (and above that, just to make it clear, the code I wrote to define ChangeColor).

Our function has a TypeScript type of Override

In Framer Classic we used CoffeeScript, a language built on top of JavaScript that was easier to use and looked cleaner (no curly braces).

In Framer X we use TypeScript.

While CoffeeScript looked quite different from JavaScript, TypeScript is JavaScript. Well, with a few additions.

The main advantage of TypeScript is that you can give variables a predefined shape, a ’type’ (hence the name of the language).

You can define, for instance, that a variable should always contain a String, or a Number, or a Boolean.

Say you have a (let) variable called totalPrice, with a type of number, that initially contains 0:

let totalPrice: number = 0;

When you then give it another numeric value…

// updating the price
totalPrice = 100;

… everything will work fine.

But when you try to set it to a String…

totalPrice = "one hundred bucks";

… VS Code will complain.

You can also define which types of parameters a function will accept. Remember our simple addition function from higher up?

We can say that the number1 and number2 parameters it accepts should always be numbers.

const addNumbers = (number1: number, number2: number) => {
  return number1 + number2
}

Back to our ChangeColor function. We give our function the type of Override.

const ChangeColor: Override = () => {
  return {
    background: "red"
  };
};

This enables VS Code to check if our code is kosher because it knows what an Override can and should contain. (That’s what we imported higher up: all the details about this Override type.)

Setting the type to Override also makes the function discoverable by Framer. Only functions of this type will appear inside Framer’s Code tab. (And, by extension, only files that contain Override functions will show up in that Code tab.)

We ‘export’ the function

By writing export before defining the function you make it so that Framer can import it and show it in its Code menu.

export const ChangeColor: Override = () => {
  return {
   background: "red"
  };
};

So if you’re writing an override and it doesn’t show up in the Code menu, one of the following statements will be true:

  1. You forgot to type it as an Override (easy to solve)
  2. You forgot to export the function (piece of cake)
  3. Your function has an error

Errors are harder to fix, but that’s why we have VS Code. Any error in your code will be underlined with a scribbly red line. Hover over it for more information.

A bit more about const

To be honest, const isn’t always a synonym for ‘immutable.’ It depends on what you’ve put inside that ‘const’ variable.

When it’s a String, Number, Boolean, or in our case, a function, then it’s true that the value can’t be ‘mutated.’

But when it contains an Array or Object, then the values inside that Array or Object can be changed.

const justAnObject = {
  text: "I’m a text string"
};

justAnObject.text = "I’m now a different text string.";

More info: Use const and make your JavaScript code better

More complicated Overrides

download the example project

Setting a property when tapped

Finally, some interaction!

On the Canvas
In the Preview

import { Override, Animatable } from "framer";

const colorValue = Animatable("#66BB66");

export const ChangeColorOnTap: Override = () => {
  return {
    background: colorValue,
    onTap() {
      colorValue.set("red");
    }
  };
};

We animate values, not properties

Now we get to touch on something important.

In Framer, you don’t animate a property directly. You animate a value that you attached to a specific property.

You might say: “But we’re not even animating!” True, but we are changing the color. It starts off as green, #66BB66, and then we change it to red.

So we first create a variable to hold the color, colorValue, that we set to the initial green color, "#66BB66":

const colorValue = Animatable("#66BB66");

Then, inside our return statement, we attach colorValue to the background property:

    background: colorValue,

Now, whenever we change colorValue, it will, in turn, change the background, because they’re bound together.

We also bind an onTap() handler to the frame.

    onTap() {
      colorValue.set("red");
    }

So that when it is tapped colorValue will be set to "red".

Again, directly setting background will not work, you have to change the value that you tied to the background property.

Something like this (trying to set the property directly) does not work:

export const ChangeColorOnTap: Override = props => {
  return {
    onTap() {
      props.background = "red";
    }
  };
};

The Animatable object

You noticed that we’re using this Animatable object, which we’re now also importing from the Framer library.

import { Override, Animatable } from "framer";

That value you want to change (or animate) should be inside an Animatable.

const colorValue = Animatable("#66BB66");

Framer will notify React of changes to an Animatable object so that React knows when to update (re-render) the screen.

(By the way, the variable can be a const because the object itself will not change, only the value we’re storing inside it.)

And to change the value, we use the Animatable’s set() function:

colorValue.set("red");

Believe me, I tried, using a simple let variable instead of an Animatable, like this…

let colorValue = "#66BB66";

export const ChangeColorOnTap: Override = () => {
  return {
    background: colorValue,
    onTap() {
      colorValue = "red";
    }
  };
};

… will not work.

Animating a property when tapped

On the Canvas
In the Preview

import { Override, Animatable, animate } from "framer";

const colorValue = Animatable("#66BB66");

export const AnimateColorOnTap: Override = () => {
  return {
    background: colorValue,
    onTap() {
      animate(colorValue, "red");
    }
  };
};

We need the animate function, so we add it to our imports.

import { Override, Animatable, animate } from "framer";

But anyway, if you type animate in your code without having it imported, VS Code will offer to add it to the import statement. (A little light bulb will pop up when you click the error.)

Obviously, the value should be an Animatable, so that we can animate it.

const colorValue = Animatable("#66BB66");

And again, we don’t animate the property itself (background) but the value that we attached to it:

      animate(colorValue, "red");

We animate colorValue to a new value: "red".

We didn’t give animate more details, so this animation will use the default settings: an ‘ease’ curve with a duration of one second.

Back to Framer’s example ‘Scale’ override

And now, we can take another look at that example that’s in every new overrides file:

import { Data, animate, Override, Animatable } from "framer"

const data = Data({ scale: Animatable(1) })

export const Scale: Override = () => {
  return {
    scale: data.scale,
    onTap() {
      data.scale.set(0.6)
      animate.spring(data.scale, 1)
    },
  }
}

It’s not too difficult, is it?

The only extra thing happening here is that, when tapped, the scale of the frame is made smaller (0.6), just before it gets animated back to the original scale of 1. (Otherwise it wouldn’t animate.)

And in this one, the Animatable, named scale, is placed inside Framer’s Data object.

Animating a property automatically

On the Canvas
In the Preview

import { Override, Animatable, animate } from "framer";

const colorValue = Animatable("#66BB66");

export const AnimateColorInstantly: Override = () => {
  animate(colorValue, "red");
  return {
    background: colorValue
  };
};

You can have an animation start right away, by kicking it off before even returning the properties to the frame.

  animate(colorValue, "red");
  return {
    background: colorValue
  };

So here we start with animating colorValue, and only then we say: “By the way, this should be the value of the background. Apply it, because it’s already changing!”

(The other way round will not work, because a return is always the end of a function.)

With this technique, the frame will animate the moment it appears. (So you can use it in click-through prototypes.)

Starting from the current value of a property

By the way, we actually don’t have to set the start color, we could read the frame’s current color.

All the frame’s properties are inside a props object that we can pass in.

Look, for example, at the Fade override in Framer’s Examples.tsx :

const data = Data({
  opacity: Animatable(1)
});

export const Fade: Override = props => {
    data.opacity.set(props.opacity)

    return {
        opacity: data.opacity,
        onTap() {
            animate.linear(data.opacity, 0)
        },
    }
}

The opacity animatable is set to a start value of 1.

But, just to be sure, the override also gets the current opacity from the frame’s props.

Often an override function doesn’t need any of the frame’s existing properties so you can leave its parameters empty: ( ).

export const Fade: Override = () => {
  ...

But when you add the props object, like this:

export const Fade: Override = props => {
  ...

You can get the current value of any of the frame’s properties.

This way we can set data.opacity to the frame’s current opacity, props.opacity, before we do anything else.

    data.opacity.set(props.opacity)

6 comments on “Overrides (pre X22)”

  • sascha says:

    Your way of explaining is amazing. Thanks for this.

  • Vsplorer says:

    hello, when I used:

    opacity: Animatable(1)

    and

    data.opacity.set(props.opacity)

    but it is alert all the time, how can I deal with it?

    thanks.

    • Tes Mat says:

      These APIs are probably not fully supported in the current version of the Framer library.
      Try to change the ‘Framer Library Version’ (see ‘File’ menu) to an older one.

      • Vsplorer says:

        Thanks for replying.
        So, how can I get the current value of a property in current version ?

        • Tes Mat says:

          Good question, because it seems that it’s not possible anymore.

          I tried with opacity, left and rotate:

          import { Override, Data } from "framer"
          
          const data = Data({
              opacity: 0,
              left: 0,
              rotate: 0,
          })
          
          export function AnimateOnTap(props): Override {
              data.opacity = props.opacity
              data.left = props.left
              data.rotate = props.rotate
          
              return {
                  animate: {
                      opacity: data.opacity,
                      left: data.left,
                      rotate: data.rotate,
                  },
                  onTap() {
                      data.opacity = 1
                      data.left = 100
                      data.rotate = 45
                  },
              }
          }

          The values will be set to the current props (so the initial 0 values will be overwritten)… but then nothing happens when the onTap() is triggered.

          When you delete the lines that get the current props:

              data.opacity = props.opacity
              data.left = props.left
              data.rotate = props.rotate

          … then the animation does work. But then, obviously, the Frame’s opacity, left and rotate are set to zero when it appears.

          BTW, I also tried with Koen Bok’s useStore hook, but that didn’t make a difference.

          Maybe somebody on the Slack or Spectrum knows how to do it. I would ask there.

Comments are closed.