Deprecated Code Component Width and Height Props
If you’re a component author, or regularly use code components in your projects, you might have run into this message in your developer console:
Deprecation notice: the component "SomeComponent" from the package "Package"seems to be using the "width" or "height" props. These properties are now deprecated and will no longer be automatically passed into componentinstances. Until this component is updated, it will run in compatibility mode,which may affect its performance.
Up until recently, code component instances had their current size in pixels passed in as the width and height props. These properties are now deprecated and Framer will soon stop providing them to code component instances.
Why were width and height deprecated?
With the release of Smart Components, and in preparation for more exciting features, we’ve had to change some of Framer’s internal functionality. These changes made it impossible to continue supporting the width and height properties without a great cost to performance. Performance matters a great deal to us, so we decided that in order to provide the best experience for our users, we needed to stop supporting props that might compromise it.
I’ve been using the width and height props. Will my component still work?
Yes, for now your component will still work. Until it’s updated to no longer use these props, your component will run in compatibility mode. It should render exactly as it used to, but may slow down projects that use it.
What do I use instead of the width and height props?
Code components will typically render inside a container known as the Component Wrapper. This container is the box you actually manipulate on the Framer canvas to give your component its position and size. If you want your component instance to always be as big as the layer drawn on the canvas, all you need to do is make sure the element you’re rendering stretches to“100%” of its container:
export function Button({ text }) { return ( <motion.div style={{ width: "100%", height: "100%" }}> {text} </motion.div> )}
What if I need the size of an element in pixels?
There are a few ways you can achieve this. Let’s say you’re trying to render an Avatar component, and you want to render a circle that fits perfectly inside the bounds of the layer on the canvas. To do this, you’d need to:
- Get the current width and height of the rendered layer
- Pick the smaller of the two
- Draw a div with a border radius set to half the value from step 2
And here’s how to do this in code:
export function Avatar() { // We'll keep the measured size in a state variable, and pick 200x200 as a default const [currentSize, setCurrentSize] = React.useState({ width: 200, height: 200 })
// Our entire component will be rendered inside a div that will be 100% of the size of the component container Framer provides. Their size will be the same as the size the user has set on the canvas. We don't have access to the Framer container from this component (it's our parent), but we do have access to the wrapper we will render, so we'll keep a ref to it. const wrapperRef = React.useRef(null)
// We'll use a layout effect to measure the size of the element we want. Layout effects run right after a render, so the browser has already had a chance to compute all layout changes, but hasn't painted them on the screen. This gives us a window of opportunity to change the layout of our element before it's displayed. useLayoutEffect(() => { // If this runs and we don't have a reference to the HTML element for the wrapper,we can't measure anything if (!wrapperRef.current) return
// We ask the browser to measure the element const size = { width: wrapperRef.current.offsetWidth, height: wrapperRef.current.offsetHeight } // If the size has changed from the default, we'll set the currentSize state variable, which will immediately kick off another render. It's important that we have this check, otherwise our component will fall into an infinite loop of checking its size re-rendering if (size.width !== currentSize.width || size.height !== currentSize.height) { setCurrentSize(size) } }) const smallerSide = Math.min(currentSize.width, currentSize.height) const radius = Math.floor(smallerSide / 2)
return ( <motion.div style={{ width: "100%", height: "100%" }} ref={wrapperRef}> <motion.div style={{ width: `${smallerSide}px`, height: `${smallerSide}px`, borderRadius: `${radius}px`, overflow: "hidden", }}> ...[the image]... </motion.div> </motion.div> )}