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.
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.
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.
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.