Component patterns
Every component has a motion vocabulary. Most ship without one.
Buttons
Scale to 0.97 on :active. 50-80ms, ease-out.
No springs on buttons in product UI. No background-color animation on press. No transition on disabled states.
Popovers and dropdowns
Enter: Scale 0.9 to 1, opacity 0 to 1. 150-200ms. Transform-origin: edge nearest the trigger.
Exit: Opacity to 0, scale to 0.95. 100-150ms. Faster than entrance.
Don't use translateY for popovers. Scale from the trigger point. Do use translateY for nav dropdowns, where "dropping down" is the right metaphor.
Tooltips
Enter: Opacity 0 to 1, scale 0.85 to 1. 100-150ms. Slight translateY (4px toward trigger).
Exit: Opacity to 0. 75-100ms. No scale on exit.
Enter delay: 300-500ms prevents flickering across toolbars. Once one tooltip is visible, the next appears instantly.
Drawers and sheets
translateX (side drawers) or translateY (bottom sheets).
Enter: 250-350ms. cubic-bezier(0.32, 0.72, 0, 1) or spring { stiffness: 400, damping: 40 }.
Exit: 200-250ms. cubic-bezier(0.4, 0, 1, 1).
Pair with a backdrop at opacity: 0.5. Don't scale drawers. A drawer slides on one rail.
Modals and dialogs
Enter: Scale 0.95 to 1, opacity 0 to 1. 200-300ms. translateY 8-12px upward. Transform-origin: centre or trigger position.
Exit: Opacity to 0, scale to 0.95. 150-200ms. Slight translateY downward.
Toasts and notifications
Enter: Translate from off-screen. 200-250ms. Spring { stiffness: 400, damping: 30 }.
Exit: Translate back or fade with scale to 0.95. 150-200ms.
Slides in from the edge it lives on. Stagger multiple toasts with layout animations.
Hover effects with CSS
transform and box-shadow only. Don't scale cards above 1.02. For list items, transition: background-color 100ms ease beats a transform.
Text state swaps
Save. Saving. Saved. A three-phase swap: old text exits, container holds, new text enters.
mode="wait" finishes the exit before starting the enter. Without it, both labels render simultaneously.
Error shake
Decaying oscillation, 400ms total. Pair with a red ring. One shake per error event.
Notification badge
Two-stage entrance: slide in, then pop to full size with overshoot.
times controls where each keyframe lands: start at 0.8, overshoot to 1.15 at 60%, settle at 1.
Success checkmark
A static checkmark says "done." A drawn checkmark says "just now."
Circle first, checkmark 300ms later. Add slight rotation (-10 to 0 degrees) and it feels written rather than displayed.