Code Overrides
A way to share data between components within Framer.
Code Overrides are higher-order components that can be used to share application state, work with real data, create advanced gestures & animations, and more.
They can be applied to almost any layer on the canvas and give you the ability to override the layer or component's props. A basic override looks like this:
import type { ComponentType } from "react";
export const withLowerOpacity = (Component): ComponentType => { // This part of the code is only run once when creating the component return (props) => { // This part runs every time the component is rendered. return <Component {...props} opacity={0.5} />; };};
This override takes in the Component or layer it's attached to, and overrides the opacity to 0.5
.
Note: the older override syntax still works, but we decided to stay as close to standard React as we could going forward, avoiding having multiple ways to do the same thing.
#Sharing Data
Overrides in Framer also allow you to share data, information, and state across the different components you attach them to.
When using Overrides to share data across components, we suggest using a simple shared hook.
import type { ComponentType } from "react";import { createStore } from "https://framer.com/m/framer/store.js@^0.3.0"
const useStore = createStore({ count: 0 });
export const withCount = (Component): ComponentType => { return (props) => { const [store, setStore] = useStore(); return <Component {...props} text={`Count ${store.count}`} />; };};
export const withIncrement = (Component): ComponentType => { return (props) => { const [store, setStore] = useStore(); const onTap = () => setStore({ count: store.count + 1 }); return <Component {...props} onTap={onTap} />; };};
If you were previously using the Data
component to share data, we now encourage you to switch to standard hook solutions (like the one above).
If React hooks seem intimidating to you at first sight, you’re not alone. They are a standard part of React and are the default way to keep track of a component's state. Let's take a look at a simple example:
const [name, setName] = useState("Koen")
In this example, name
holds the current value. By default, we set it to "Koen"
at the end of the line.
You can update the name
by calling setName("Hunter")
.
If you're having trouble understanding React, we've written an entire book just for you! Framer's Guide to React is the perfect resource to learn enough about React to become dangerous. It's written from a Designer's perspective, mapping out everything you'll want to know to start writing your own Overrides.
Additionally, you can find more tutorials on learning React here.
#Recipes
#Scroll Animations
Overrides can be used to animate elements based on interactions with other elements. In this case we add the withScroll
Override to a Scroll component on the canvas. When scrolled, the Scroll component maps its scrollOffset to the global MotionValue scrollOffset
which we can use to animate values in other Overrides. By using a MotionValue, all our animations are incredibly performant by default.
In withHorizontalParallax
we use useTransform
to map the x position of the element to 25% of the scrollOffset
MotionValue, creating a parallax effect.
In withFadeByScroll
we use useTransform
to fade the opacity of the element when scrollOffset
is between 50 and 200 (mapped to 0-1). You can change these values as you'd like to create the style of animation you're looking to create.
import type { ComponentType, ReactPropTypes } from "react"
import { useLayoutEffect, useRef } from "react"import { motionValue, useTransform } from "framer"
const scrollOffset = motionValue(0)
export function withScroll(Component): ComponentType { return (props) => { const ref = useRef<HTMLDivElement>(null)
// Reset scroll offset on mount useLayoutEffect(() => { scrollOffset.set(0) }, [])
const onScroll = () => { if (!ref.current) return scrollOffset.set(ref.current.scrollTop) }
return <Component {...props} ref={ref} onScroll={onScroll} /> }}
export function withHorizontalParallax(Component): ComponentType<any> { return (props) => { // Map x position to 25% of scroll offest const x = useTransform(scrollOffset, (latest) => latest * 0.25)
return <Component {...props} style={{ ...props.style, x }} /> }}
export function withFadeByScroll(Component): ComponentType<any> { return (props) => { // Fade in when scroll offset hits 50 // Finish fade when scroll offset is 200 const opacity = useTransform(scrollOffset, [50, 200], [0, 1])
return <Component {...props} style={{ ...props.style, opacity }} /> }}
#Variant Cycling
By applying Overrides to smart components with Variants you can gain an extra layer of control, allowing you to use logic & events from other Overrides to animate between them.
A basic example here shows how can use an Override to cycle between Variants of a smart component, from here you can log the current variant to the console or add additional logic based on the Variant switches.
import type { ComponentType } from "react"import { useCycle } from "framer-motion"
export function withLocalVariantState(Component): ComponentType { return (props) => { // Cycle between variants on Tap const [variant, cycleVariant] = useCycle("Active", "Inactive")
console.log(`Switched to Variant ${variant}`)
return <Component {...props} variant={variant} onTap={cycleVariant} /> }}
From there, we can set up a shared store using createStore
that we use to synchronise the Variant of multiple Smart components with the Overrides applied.
import type { ComponentType } from "react"import { useCycle } from "framer-motion"import { createStore } from "https://framer.com/m/framer/store.js@^1.0.0"
const useStore = createStore({ variant: "Active",})
export function withSharedVariantState(Component): ComponentType { return (props) => { // Uses the Variant set on the shared store const [store] = useStore()
return <Component {...props} variant={store.variant} /> }}
export function withToggleSharedVariantState(Component): ComponentType { return (props) => { const [store, setStore] = useStore()
// Cycles the variant set on the shared store function toggleVariant() { setStore((prevState) => ({ variant: prevState.variant === "Active" ? "Inactive" : "Active", })) }
return ( <Component {...props} variant={store.variant} onTap={toggleVariant} /> ) }}