The small moments of feedback that make an interface feel alive — toggles, ripples, toast notifications, floating labels, accordions. Click, hover, and type on any example below, then copy the real code.
A micro-interaction's whole job is to answer a question the user didn't consciously ask — did my click register, is this loading, did that save. The moment it starts drawing attention to itself instead of the task, it's working against the interface, not for it. The five categories below cover the situations that come up in almost every real product.
Anywhere a user sets a binary or single-choice state — settings, filters, ratings. The state change itself should be instant to register (under 250ms) so the control never feels laggy to operate.
Confirms something happened after an action completed — a save, a copy, a validation error. This is the category most worth getting right: silence after an action reads as "did that work?", which is worse than almost any animation.
Direct response to a click or tap — ripple, spinner, icon morph. These should start the instant the pointer event fires; even a 100ms delay before feedback begins reads as unresponsive.
Signals what's interactive before a click happens — card lifts, tooltips, floating labels. Every hover effect needs a matching :focus-visible state, or keyboard users get none of the same feedback mouse users do.
Reveals or reorganizes content — accordions, tabs, dropdowns. These carry real information in their motion (what expanded, what's now active), so the animation should track the actual layout change, not just fade over it.
transform and opacity wherever possible — they run on the compositor and stay smooth even on cheap hardware, unlike width/height/top/left, which force layout recalculation every frame. Keep most interactions under 300ms — longer starts to read as slow rather than polished. And wrap non-essential motion in @media (prefers-reduced-motion: reduce) — keep the state change, drop the movement, for users who've asked their OS to reduce motion.
A small, contained moment of feedback triggered by a single user action — a button that ripples on click, a checkbox that draws its own checkmark, a toast that confirms a save happened. One trigger, one short response, no navigation. Its job is to answer a question the user didn't consciously ask: did that work?
Not if you animate the right properties. transform and opacity are handled by the compositor and stay smooth even on low-end devices. Animating width, height, top, left, or box-shadow directly forces layout recalculation on every frame and can visibly stutter — prefer a transform-based equivalent wherever one exists.
150–300ms for most hover/click feedback, up to 400–500ms for larger movements like a toast sliding in or an accordion expanding. Past ~500ms it starts to feel like the interface is slow, not polished.
Fewer than people assume — 18 of the 25 examples on this page are pure CSS. Toggles, checkboxes, star ratings, floating labels, accordions (via the native <details> element), and tooltips all work with just :checked, :focus, :hover, and sibling selectors. JavaScript earns its place for things with no matching CSS state — a toast after an async action, a ripple centered on exact click coordinates, or a tab indicator that measures another element's width.
Wrap non-essential motion: @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; } }. Keep the state change — a checkbox becoming checked, a toast appearing — just remove the movement getting it there.