Delivering Consistent Animations with a Design System Library

Brett Holcomb
Intuit Engineering
Published in
6 min readApr 25, 2019


Sample of animations from the QuickBooks Animation Library

A few months ago at Intuit my motion designer friend (Brandon Wall) and I (design technologist) wanted to make it easier for developers to implement the motion designs Brandon had created in After Effects. To help them out, and to have an interactive preview for our design team, we built the QuickBooks Animation Library.

Our approach to animation lately has been to use Lottie for more complex storytelling animations, and CSS for almost all UI animation on the web. We previously used GSAP for some animations, but lately for most projects we’ve found we can design around the constraints created by CSS animation.

Performant CSS animations limit you to primarily animating 4 properties: position, scale, rotation, and opacity. You’re also limited in how you can chain together multiple animations or animate multiple properties independently. Teams usually reach a point where they turn to a JavaScript solution for more complex animations, but CSS is still great for most UI animations.

A more complex animation made in After Effects that we shipped using the Lottie-Web JS library
A (somewhat complex) loading spinner built using CSS | CodePen

Inspiration to build a library

In the past, we’ve worked with developers 1 on 1 to share motion specs that included animation curves, timings, and delays. This worked well when building components that were easily adopted by other teams because new teams using the components never even have to think about UI animation. There were a few downsides though:

  • QuickBooks has a number of different design & engineering teams and it’s difficult to work with all of them directly
  • 3rd party vendors didn’t have easy access to existing animation specs or coded animations
  • Motion specs were often created in After Effects or Principle; Adapting them to new projects required specialized design skills
  • Motion specs weren’t always available as code; Using them required specialized developer skills

With those considerations in mind, we were inspired by the simplicity of Animate.css and similar animation libraries. There are a number of similar libraries available, but we think sharing our take on them will help contribute to the field since we have a consistent motion aesthetic and are a bit more constrained than the other libraries available. Many existing libraries approach motion design with the philosophy that more motion is better.

How we built it

One thing we really liked about these libraries was the interactive previews, so the first thing we did was include those:

Animation previews — try them out!

Working in SCSS, we worked backward from some of the existing motion work to systemize how we defined our animations. Here’s the structure of the library in 4 layers:

1. Motion variables. These include values to animate between and common durations, but the animation easing curves are most critical since they contribute much of the character to UI animations.


2. Keyframes. These define the values to animate from and to.


3: Base animations. Built using our motion variables and keyframes.


Note that the entrances use animation-fill-mode backwards so that an animation delay works properly and we also don’t need to worry about the animation styles after the animation has run. Similarly, the exit animations use animation-fill-mode forwards so an element will stay hidden even if stays in the DOM.

4: Semantic mappings. To make our UI animations easier to manage and update in the future, we also created semantic mappings so hopefully, our users won’t have to think about choosing the appropriate animation for a modal, flyout, menu, etc. These can be tricky though since we’ve found these terms aren’t always used consistently and new visual styles can create cases where the semantic mapping doesn’t appear as intended.

qbal-semantic-classes.scss — This also gives us the chance to address accessibility. We know the trowser animation covers a large area of the screen, so we can use the prefers-reduced-motion media query to make it a simple fade.

In future versions, we plan to make the mappings of variables + keyframes to the base animations and then to semantic animations more transparent in the documentation. I’ve already had people view the documentation and ask me: “Which curve is this?”

Options for using the animation library

We started with SCSS mixins so you can add animations without having to add classes to your HTML:

We also provide a CSS file for workflows where adding classes directly is easiest:

Finally, we recently added the option to use the animation library with styled components:

A frontend developer experienced with animation could also just import the motion variables (via SCSS or styled-components) as a starting point for further experimentation. See the usage documentation for more detail.

Warning for CSS minifiers!

One issue we ran into when using CssNano to create a minified version of the CSS is that by default it will rename your keyframes from qbal-FadeEnter, qbal-RightEnter, and qbal-LeftEnter to a, b, and c. We’ve added a configuration file so the keyframe names don’t get minified, but be careful if you’re generating your own CSS and it gets minified. This creates some comically bad experiences when combined with other CSS files that also have minified keyframe names:

Uh oh. Our CSS loading spinner got the wrong keyframes!


This is one approach to systematizing animation code for the web. Developers have a wide range of experience with implementing animations, so we’ve mostly focused on making it as easy as possible to drop in the appropriate animation. Onboarding designers and developers is an ongoing process though, so there are a few questions we’re still working on.

  • Will we need to provide additional guidance to prevent teams from adding too many animations?
  • How can we best encourage teams to default to the appropriate semantic animation when one is available?
  • Do we need to provide additional guidance or examples for altering the animations for marketing and single-use applications where we might want different keyframes or more theatrical timing?
  • For the QuickBooks platform specifically, how do we best provide training in using react-transition-group and styled-components?

To share your thoughts, leave a comment below or join the Animation at Work Slack and find me in #CSS or #libraries. You can also message me directly: @bholco.

Related Work

Both of these have some pretty reasonable animations, but in some cases, it feels off to see the same decelerating easing on both entrance and exit animations. Animate.css also does some translations over 100% the height of the element, which can lead to very different distances covered depending on the height of the element being animated.