The gap between an app that feels cheap and one that feels expensive is usually 200 milliseconds of feedback. Not a redesign. Not a new font. Just the small stuff: what happens when you press, hover, submit, or wait. Here’s where that budget goes.
Feedback under 100ms
When someone clicks, they need to know it registered before they consciously notice the delay — that window is about 100ms. Under 100ms feels instant. So the press state, the highlight, the spinner appearing: fire them immediately, on the same frame as the input. Never wait for the network to confirm before you show that something happened. Paint the optimistic state first and reconcile later.
Keep transitions near 200ms
State changes that move or fade — a dropdown opening, a tab sliding, a card expanding — want 150 to 250ms. Faster than 150ms and the eye can’t track it, so it reads as a jump. Slower than 300ms and you’re making people wait on your taste. Pick 200ms as your default and deviate only with a reason. Bigger distances get a little longer: a full-screen sheet can take 300ms, a checkbox 120ms.
Press it down
The cheapest win in the whole list: scale the element down slightly while it’s pressed. Use active:scale-[0.98] on a button, or 0.97 for something chunky like a card. It mimics a real, physical push, and paired with a fast color shift it makes every tap feel connected to the pixel under your finger. Keep it subtle — go below 0.95 and it looks broken.
When not to animate
Restraint is the senior move. Skip the motion when it gets in the way:
- Anything a user is waiting on — search results, validation errors, a price update.
- The same element twice in one interaction; pick one moment and commit to it.
- Everything decorative, once
prefers-reduced-motion: reduceis set.
The best micro-interactions are the ones people feel but never notice. Add them where they confirm an action, and nowhere else.