Animations for Libra

With proper animations, any product can feel more qualitative, faster, and more predictable. But they can also do the opposite: slow down users, annoy them, and induce uncertainty.

Adding animations may feel like a reasonable idea, but we should always ask: Is adding this animation going to help or distract the user?

Animations must earn their place

There are only three good reasons to animate something:

  1. Feedback – confirming that an action registered
  2. Orientation – showing where something came from or went
  3. Focus – drawing attention to a change the user would otherwise miss

If an animation does none of these, it is decoration. Decoration is fine on a landing page — in a tool people use daily, it is a tax they pay on every interaction. Sometimes the best animation is no animation.

Frequency

Think about what the user wants to achieve and how often they will see an animation. A hover effect is nice, but if used multiple times a day, it would likely benefit the most from having no animation at all.

A rule of thumb: the more often an action is performed, the less it should animate. Something seen once (onboarding, a success moment) can afford expressive motion. Something used dozens of times a day (switching tabs, expanding rows, a command palette) should be instant. And never animate in response to keyboard input — keyboard users are your fastest users, and any transition makes the UI feel like it is lagging behind them.

Imagine you interact with this list often during the day.

What not to animate

High-frequency, goal-oriented actions: tab switches, list navigation, autocomplete, frequently used panels. Text content the user is waiting to read — don’t fade in search results, they want the data, not a reveal. And consecutive identical elements: the first tooltip in a group may fade in after a delay, but moving to the next one should show it instantly.

Hover across the icons — only the first tooltip waits and fades.

What should be animated

Overlays entering and exiting (modals, popovers, toasts) — sudden appearance is jarring, and motion clarifies where the element came from. Elements appearing or disappearing inside a layout — without a collapse, content teleports and users lose their place. State changes on the same element, loading indicators, and changes that happen outside where the user is currently looking.

Animated (200ms)

Draft NDA for Meridian
File response by Friday
Update case timeline
Send invoice reminder

Instant

Draft NDA for Meridian
File response by Friday
Update case timeline
Send invoice reminder
Removing an item explains the reflow instead of teleporting the list.

Origin

An animation should always depict where an element is coming from — and, on exit, where it returns to. A menu grows out of the button that opened it, a side panel slides in from the edge it lives at, a toast rises from the corner it rests in. When motion matches spatial reality, users build a mental model of where things live in the interface; when a popover blooms from its own center, the motion tells them nothing.

In practice this means setting transform-origin to the trigger, not the element’s center — Bits UI exposes it as a CSS variable like --bits-floating-transform-origin — sliding panels from their anchored edge, and letting dismissed elements exit toward the place that summoned them.

The menu should scale from its trigger, not from its own center.

Duration

Stay under 300ms for almost everything; 150–250ms is the sweet spot for UI transitions, and hover or color changes should be around 100–150ms. Scale duration with size and distance: a checkbox tick takes 100ms, a full-height panel can take 250ms — same perceived speed, different durations. When in doubt, make it faster. Nobody has ever complained that a dropdown opened too quickly.

Same animation, 150ms vs. 400ms — the slow one makes the UI feel unresponsive.

Easing

Pick easing by what the element is doing. Entering or exiting the screen: ease-out, so the UI responds immediately and settles gently. Moving while staying on screen: ease-in-out. Hover and color transitions: ease. Never linear for UI (spinners excepted), and almost never ease-in on its own — it makes the start feel sluggish, exactly where responsiveness matters most.

ease-out
ease-in-out
linear
The same movement with ease-out, ease-in-out, and linear.

Craft details

Never animate from scale(0) — start at 0.9–0.97 with a fade instead. Exits should be faster than entrances: the user asked for the thing to go away, so get out of the way. Animate only transform and opacity so frequent animations never jank, and every animation must be interruptible — never block input while something moves.

Press feedback is the cheapest win of all: a subtle scale-down on active makes any control feel physical, with no JavaScript at all.

Press and hold — the button scales to 0.97 while active.
Scaling from 0 looks cartoonish; scaling from 0.95 feels natural.

Accessibility

Respect prefers-reduced-motion: every animation needs a reduced variant, usually a fast fade or nothing at all. And motion must never be the only carrier of information — pair it with a state that persists, like a color, icon, or label change.

A checklist before shipping any animation

Does it give feedback, orient, or direct focus — or is it decoration? Will users see it twenty times a day? Is it keyboard-triggered? Is it under 300ms with the right easing? Does its motion depict where the element comes from? Does it only touch transform and opacity, and can it be interrupted? Does it degrade under reduced motion?

If an animation survives all of that, ship it. Most won’t — and that’s the point. The product will feel faster and more polished with ten deliberate animations than with a hundred reflexive ones.