profile

Build UI

Framer Motion: Refactoring with variants + Course info!

Published almost 2 years ago • 3 min read

Hi there! You're receiving this email because you signed up to get updates about our upcoming Framer Motion course. If you'd rather not get them please feel free to unsubscribe – we only want to share this with folks who are still interested!


Hey everyone –

I’m super excited to be sending out our first update about our upcoming Framer Motion course!

We’ve had a productive few weeks kicking off our demos, and I wanted to give you a little behind-the-scenes peak at our first lesson, the check animation from the beautiful application Things – and how we improved our code using variants.

Discovering a multi-stage animation

In Things, there is a satisfying "check" animation whenever you complete a todo:

Check animation in Things

It turns out this animation actually has three separate stages:

In the first stage the button scales up, in the second stage the checkmark draws itself and fades to blue, and in the third stage the background fades out.

This led us to some pretty interesting orchestration challenges within our Framer Motion code.

First pass: Ternaries everywhere!

Let's start by looking at how we animated the check mark.

Framer Motion makes this quite easy: all we have to do is animate a path element's `pathLength` from 0 to 1:

This gives us a pretty awesome check animation:

Of course, we want the check to be based off of React state so that we can toggle it. So let's use a ternary to conditionally set the path's length:

This works great! Whenever the `checked` state updates, the check is animated.

Now, in the case of Things there's much more to the animation than just the path length. We need to animate other properties like opacity and color; we need to set different timings based on whether the box is being checked or unchecked; and we need to use a delay so the checkmark waits until the second stage of the animation to begin.

While this works, all these ternaries are hard to read. Can you tell me what happens when you uncheck the box by looking at this code?

We needed a way to make our animation code more readable.

Refactoring to variants

Framer Motion has a feature called variants that lets you assign a name to a set of animated properties. It’s great for adding more clarity to complex animations.

Here’s our same animation written with variants:

Now we can clearly see what happens when we uncheck the box by looking at the `unchecked` variant: the pathLength and opacity animate to 0 and the color animates to gray in 0.5 seconds.

A lot easier than before, right?


The thing about animations with lots of details is that they get complex, really fast. Details means lots of different properties with different delays and transitions, and these details often have to be orchestrated with each other. Variants let us express these complex animations in a readable way.

More importantly, variants are much easier to tweak and change. If we need to add a new animated property to the checked state, we know exactly where it should go.

Variants let us decouple what state an element should be in (e.g. checked) from what it means for an element to be that particular state (e.g. its pathLength should be 1).

The actual animation from Things is quite complex – each element-variant-property often has its own set of durations, delays and easings. In total we defined over 30 unique properties – all while using the same two variants, checked and unchecked.

Refactoring all of our code to use variants is what really let us start finessing each stage of our animation to match the native one from Things. The result is nearly indistinguishable.

The course – 6 high-fidelity component walkthroughs

The course we’re building will teach you how to build six separate components, from scratch, step-by-step, just like the checkbox animation from Things. For each component you’ll get a video walkthrough as well as full access to the component’s source code.

One thing I’ve learned from publishing more consistently to my YouTube channel this year is that people like details. So, we’re sourcing our component ideas from some of our favorite, most-polished apps, and making sure we deliver detailed, high-fidelity reproductions.

We can’t wait to keep building out these demos – we continue to be more impressed by Framer Motion the more we use it.

Till next time!

– Sam and Ryan

Build UI

by Sam Selikoff

Subscribe to stay updated on all the latest content from Build UI.

Read more from Build UI

Learn all about Search Params with React Server Components in our latest blog post, and check out our most recent podcast episode for our thoughts on React 19's upcoming features. Instant Search Params with React Server Components Read now → Out-of-order streaming in React Watch now → Asset loading in React Watch now → Podcast - Blog Post Club: React Labs – What We’ve Been Working On Watch now → Podcast - Instant URL search params in Next.js Watch now → Podcast - React Deep Dive:...

21 days ago • 1 min read

Dive into free videos on Radix, Remix, and Server Components, and catch our latest podcast episode where we talk through React's new cache function. Building an Elastic Slider with Framer Motion and Radix Watch now → Why you can't set cookies in Server Components Watch now → React's new cache function Watch now → Optimistic UI in Remix Watch now → Podcast - React Cache Deep Dive Watch now → Podcast - Advanced Radix UI and Blog Post Club React Server Watch now → And in case you missed it, last...

about 2 months ago • 1 min read

Hey there! I've got some exciting news to share today: Advanced Radix UI – my newest course – is now live! Clocking in at 2 hours and 13 minutes across 35 chapters, you’ll learn how to use Radix to build four completely custom UI components: a Switch, a Selector Group, a Toast, and a Slider: Each component has a completely custom design using Tailwind, and there's also some slick animation and interactions we build with React and Framer Motion to enhance what Radix gives you out of the box....

2 months ago • 1 min read
Share this post