Overriding Design Components
Only in legacy projects
Design components were replaced by Smart Components. So when you now create a component on the canvas (⌘K / Ctrl+K), it’ll be a smart one. Existing design components will continue to work as before , but only in legacy projects (projects created before the launch of Framer for Developers).
The examples on this page also use the older legacy overrides; simply because the new HOC overrides don’t work in a legacy project.
Overriding component instances
We’ll override a few instances of this first design component: a ‘Buenos Aires’ card with a picture of the Obilisco.

I added custom properties for the photo and title and dubbed them Picture
and Name
.

Overriding custom properties
Now that Picture
and Name
became properties, I can change them with overrides.

But you might say: “Why even use overrides to do this? You can change the image and text directly in the Properties Panel, without writing code!”
Well, with an override I can pull in an online image, like this one from Flickr:
export function Kyiv(props): Override {
return {
Name: "Kyiv",
Picture:
"https://live.staticflickr.com/4527/27119793019_7f465c3ec8_z.jpg",
}
}
(I’m not using the full-size image but one of the smaller versions.)
And I can use global parameters. I can, for instance, change the image format or size of all the pictures at once, by putting those values in a data object.
const appState = Data({
format: "jpg",
width: 315 * 2,
height: 160 * 2,
})
export function Amsterdam(props): Override {
return {
Name: "Amsterdam",
Picture:
"https://images.unsplash.com/photo-1459679749680-18eb1eb37418?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9" +
`&fm=${appState.format}&w=${appState.width}&h=${appState.height}&fit=crop&crop=edges`,
}
}
export function Antwerp(props): Override {
return {
Name: "Antwerp",
Picture:
"https://images.unsplash.com/photo-1556654953-3719bfc8db16?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9" +
`&fm=${appState.format}&w=${appState.width}&h=${appState.height}&fit=crop&fp-y=.7`,
}
}
These Amsterdam and Antwerp pictures are from Unsplash.
The Unsplash API uses imgix to dynamically resize images. This means you can do things like cropping an image to a predefined size. You can crop with a certain focal point as the center (see the Antwerp example), crop to a face in the picture, or let the API decide how best to crop (the Amsterdam example).
Overriding common properties
And you can, of course, also override the standard frame properties. Here I changed the card’s radius
to 0
:

export function AntwerpBorderRadius(props): Override {
return {
Name: "Antwerp",
Picture:
"https://images.unsplash.com/photo-1556654953-3719bfc8db16?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9" +
`&fm=${appState.format}&w=${appState.width}&h=${appState.height}&fit=crop&fp-y=.7`,
radius: 0,
}
}
As always, when overriding a CSS property that’s not in the <Frame>
API, you can do it on style
, like here with the borderTopRightRadius
:

export function AntwerpBorderRadius(props): Override {
return {
Name: "Antwerp",
Picture:
"https://images.unsplash.com/photo-1556654953-3719bfc8db16?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9" +
`&fm=${appState.format}&w=${appState.width}&h=${appState.height}&fit=crop&fp-y=.7`,
style: {
borderTopRightRadius: 80,
},
}
}
Overriding the primary
When you attach an override to a component’s primary, in other words, the design component itself, it will also be applied to all its instances.
The below override, Container()
, is only applied to the primary (the first card, Cabellito). Its whileHover
animates the width
and height
of the component and gives it a shadow
.
export function Container(): Override {
return {
animate: { height: 70, shadow: "0px 0px 0px 0px rgba(0, 0, 0, 0)" },
whileHover: {
height: 160,
width: 400,
zIndex: 1,
shadow: "0px 5px 13px 0px rgba(0, 0, 0, 0.5)",
},
transition: { ease: "easeInOut" },
}
}
And it also changes the zIndex
so that the currently active instance (or more precisely: its shadow) appears in front of its neighbors.

But there’s a second override, attached to the background picture inside the component. It changes the opacity
and saturation of the photo, also with a whileHover
.
export function Photo(): Override {
return {
initial: { opacity: 0.5, filter: "saturate(10%)" },
whileHover: { opacity: 1, filter: "saturate(100%)" },
}
}
I applied both overrides to the primary, which is enough to give all the instances the same behavior.
Cloning child frames
This is a more advanced technique which you’ll rarely need, but it’s always good to know what’s possible.
As you know, each element on the canvas can only have one override attached to it. That’s why I had to use two separate overrides in the above example. One for the component itself, and a second one for the picture inside it.
In this next example, there’s just one single override applied to the primary. It resizes the component itself, changes the saturation and opacity of the picture inside it, and hides the text.

Here’s the trick: every component has a children
property with an array of the elements it contains. And you can override that property, you can change a component’s children.
This design component has two children: the background Picture
and a Name
text layer.

Name
and Picture
children React has a function to map over this children array: React.Children.map()
. And we can look at their props.name
to know with which child we’re dealing. (This name
property contains the name you gave the element in the Layers Panel.)
export function OverridingChildFrames(props): Override {
return {
// Animate the Frame itself
…
children: React.Children.map(props.children, child => {
if (child.props.name === "Picture") {
// Apply an animation to the picture
} else if (child.props.name === "Name") {
// Hide the text
} else {
// It’s some other child: do nothing
}
}),
}
}
There’s only one catch: you can’t directly change a child’s properties like you can with the parent. You need to make a copy of the child, a clone (with React.cloneElement()
), and change (or add) properties while doing this.
So, when the child is a "Picture"
, I clone it and add an animate
for its opacity and saturation. And when it’s a "Name"
, I clone it and hide the text
when needed (by setting it to ""
).
export function OverridingChildFrames(props): Override {
const [hover, setHover] = React.useState(false)
return {
// Hover events + animating the Frame itself
…
children: React.Children.map(props.children, child => {
if (child.props.name === "Picture") {
return React.cloneElement(child as any, {
animate: {
opacity: hover ? 1 : 0.5,
filter: `saturate(${hover ? 100 : 10}%)`,
},
})
} else if (child.props.name === "Name") {
return React.cloneElement(child as any, {
text: hover ? "" : props.text,
})
} else {
return React.cloneElement(child as any)
}
}),
}
}
… and in the else
case, when it isn’t a "Picture"
or "Name"
, it just gets cloned with no changes.
Notice that I’m not using onHover
animations anymore. Since everything is now in one and the same override, I can use a global hover
state which triggers all the animations at the same time.
export function OverridingChildFrames(props): Override {
const [hover, setHover] = React.useState(false)
return {
onHoverStart() {
setHover(true)
},
onHoverEnd() {
setHover(false)
},
…
// Animating the frame itself + cloning the children
}
}
Here’s the complete override, including the animate
for the container frame:
import { Override } from "framer"
import * as React from "react"
export function OverridingChildFrames(props): Override {
const [hover, setHover] = React.useState(false)
return {
onHoverStart() {
setHover(true)
},
onHoverEnd() {
setHover(false)
},
animate: {
height: hover ? props.height : 70,
width: hover ? 400 : props.width,
zIndex: hover ? 1 : 0,
shadow: hover
? "0px 5px 13px 0px rgba(0, 0, 0, 0.5)"
: "0px 5px 13px 0px rgba(0, 0, 0, 0)",
},
children: React.Children.map(props.children, child => {
if (child.props.name === "Picture") {
return React.cloneElement(child as any, {
animate: {
opacity: hover ? 1 : 0.5,
filter: `saturate(${hover ? 100 : 10}%)`,
},
})
} else if (child.props.name === "Name") {
return React.cloneElement(child as any, {
text: hover ? "" : props.text,
})
} else {
return React.cloneElement(child as any)
}
}),
}
}
4 comments on βOverriding Design Componentsβ
Leave a Reply
You must be logged in to post a comment.
Hey, I can’t seem to find any example for overriding the color of the Text component. Am I missing something? Thanks
I see you found an answer on the Discord. Iβll add it here for completion.
Text is not yet very flexible and always black, but you can override its
text
and add styling in a<span>
:Or you can use Jordan Dobsonβs Text Color Tool package.
I did, I was impatient. Thanks for the book, amazing resource!
Thanks π