23 Apr 2025
---> TL;DR: height:'auto'
is a thing in Framer Motion, and it changed everything
Twenty-eight days, six hours, forty-two minutes, twelve seconds.
That’s how long it felt like I spent trying to measure the height of a div manually before realizing Framer Motion just... handles it. And by 'handle it,' I mean it gave me an animation that worked the first time. No useRef
, no scrollHeight
, no setTimeout
no confusion at all, unlike that time I woke up on a putting green with no idea how I got there. Just smooth, expanding UI bliss with height: 'auto'
. Wait... Who woke up on a putting green?
I love the look of a section that expands smoothly, like when you click a category and the content unfurls beneath it. (Is that the right word? Maybe not. But it fits my vibe.)In my case, I was mapping out categories, each opening up a group of feature rows. Each row had content that could grow, including a video player that revealed itself with a button click. So I used useRef
to measure the height on open. It mostly worked... until it didn't. Nested videos broke everything. The ref
wouldn't pick up the change fast enough. scrollHeight
came back stale. I threw in setTimeout
. I was trying to force the DOM to bend to my will.And that’s when Donnie's voice popped into my head: There are other things that need to be taken into account here, like the whole spectrum of framer motion.Wait... Framer Motion?
So the idea is: when new content renders, use the ref to measure scrollHeight
, then animate your container to that height. It works in many cases.It works… until it doesn’t. And that’s when the doubt sets in. And suddenly you’re staring at your console log like Grandma Death at her mailbox, waiting for a message that means something this time. Not just in your code, but in your commitment to layout animation as a concept. I was questioning my commitment to Framer Motion. Dev tip: If you ever want to see what else you can play with in a ref, run console.log(ref.current)
it opens up a whole world of DOM properties you can poke at. Height, width, offset, class list, children, you name it. Great for tinkering.
There’s a scene in Donnie Darko where Kitty Farmer shouts:Sometimes I doubt your commitment to Sparkle Motion!”That line echoed in my head as I was struggling with this issue... and then, like through a wormhole, it was presented to me: height: 'auto'
. Surely that can’t work. Browsers don’t animate to auto
, right? But I tried it anyway.
initial={{ height: 0, opacity: 0 }}
animate={{ height: 'auto', opacity: 1 }}
exit={{ height: 0, opacity: 0 }}
transition={{ duration: 0.3 }}
transition={{ duration: 0.3 }}
style={{ overflow: 'hidden' }}
And it just… worked. Important addition is that overflow: 'hidden'
keeps everything nice and tucked inside the surrounding div.No useRef
, no measuring, no delay tricks. Framer Motion did the layout calculation behind the scenes and gave me the smooth unfurl I had been searching for. height: 'auto'
in a motion.div
, it temporarily measures the height before and after render, and animates the change .It’s like scrollHeight
, but with none of the stress. It also plays beautifully with AnimatePresence
, so your exits are as clean as your entrances.† † This excludes Frank’s. useRef
Forever?useRef
incredibly useful, especially when working with video elements for example. I’ve used it to access the duration of a video. It’s great for tapping into properties you can't reach through state or props alone. But when it comes to animating height based on content, especially when that content changes dynamically. I’ve stopped reaching for ref
. If height: 'auto'
gets me there without the hassle? I’m in. Sometimes, you just gotta trust the Motion. After all, it's not the size of the ref
it's the Framer of the Motion... or something like that.