Anatomy of a micro-interaction
Every small feedback moment has four parts — trigger, rules, feedback, and loops. Name them and you can design any of them on purpose.
In one line: a like button, a toggle, a copied-to-clipboard toast — every one is built from the same four parts, and once you can name them you can design each on purpose instead of by accident.
What it is
A micro-interaction is one small, self-contained moment where the interface responds to a single thing you did. Tapping a heart to like a post is the classic example. It feels like one act, but underneath it has four distinct parts.
The trigger is what starts it — your tap, click, or keypress. The rules are what the system decides to do in response: which state flips, what changes, and what's not allowed. The feedback is what you actually see and hear — the heart filling, a number ticking up, a little pop. And the loops & modes describe behavior over time: what happens when you do it again, and whether the result sticks around after you leave.
Most interfaces ship the trigger and the feedback and quietly skip the other two. That's why so many buttons feel half-built: they animate, but the rules are vague (does a second tap undo it?) and the state doesn't persist.
Why it matters
Naming the parts turns "make it feel nice" into four answerable questions. When a control feels off, the fault is almost always in one specific part: the trigger area is too small, the rules let you double-fire, the feedback is too slow, or the state silently resets on reload.
This vocabulary comes from interaction design and it scales. The same four parts describe a toggle, a pull-to-refresh, a form field that validates as you type. Once you see the skeleton, you stop reinventing it and start tuning it. The feedback gets most of the attention because it's the visible part — but a beautiful animation on top of sloppy rules still feels broken. Design all four and the moment feels considered, not decorated.
See it
Tweak it3
How it works
Walk the same like button through its four parts:
- Trigger. Keep it a real
<button>so a pointer tap and a keyboard Space/Enter both fire the same handler — you get the input handling for free instead of wiring it twice. - Rules. On trigger, flip
liked, adjust the count by one, and mirror the state intoaria-pressed. The key rule is reversibility: a second activation undoes the first, so the count never drifts and you can't double-like. - Feedback. The heart fills and gives a quick springy pop on like, then returns calmly on unlike. Only
transform(scale) andopacity/fillchange, so the animation stays on the compositor and never reflows the row. - Loops & modes. Every toggle re-runs the pop — that's the loop. The mode is the longer-lived state: in a real app the liked flag is saved and shown again when you return. The animation is momentary; the truth it points at is persistent.
Build it
/* TRIGGER: a real button gets pointer + keyboard for free */
.like-btn {
display: inline-flex;
align-items: center;
gap: 0.5rem;
}
.like-btn:focus-visible {
outline: 2px solid var(--ring, #6366f1);
outline-offset: 2px;
}
/* FEEDBACK: the heart fills (rules toggle .is-liked on the element) */
.like-heart {
transform: scale(1);
transition: transform 160ms ease;
}
/* LOOPS: re-running this class restarts the pop on each like */
.like-btn.is-liked .like-heart {
animation: heart-pop 320ms cubic-bezier(0.22, 1, 0.36, 1);
}
@keyframes heart-pop {
0% { transform: scale(1); }
45% { transform: scale(1.35); } /* overshoot, then settle */
100% { transform: scale(1); }
}
/* a11y: drop the pop entirely; the fill still happens instantly */
@media (prefers-reduced-motion: reduce) {
.like-heart,
.like-btn.is-liked .like-heart {
transition: none;
animation: none;
}
}import { useState } from "react";
import { motion, useReducedMotion } from "motion/react";
export function LikeButton() {
const reduce = useReducedMotion();
// RULES: liked state + count, kept in sync and reversible
const [liked, setLiked] = useState(false);
const [count, setCount] = useState(128);
// TRIGGER: one handler for tap and keyboard, via a real <button>
function toggle() {
setLiked((prev) => {
setCount((c) => c + (prev ? -1 : 1));
return !prev;
});
}
return (
<button type="button" aria-pressed={liked} onClick={toggle}>
{/* FEEDBACK: springy pop on like; LOOPS: re-runs every toggle */}
<motion.span
aria-hidden
initial={false}
animate={reduce ? { scale: 1 } : { scale: liked ? [1, 1.35, 1] : 1 }}
transition={
reduce
? { duration: 0 }
: { type: "spring", stiffness: 600, damping: 14, mass: 0.6 }
}
style={{ display: "inline-block" }}
>
{liked ? "♥" : "♡"}
</motion.span>{" "}
{count}
</button>
);
}Make it yours
Use the controls beside the demo above to change highlight part, pop strength, and starting like count — each change updates the example live.
Experiment in the playgroundReproduce it with an LLM
Reproduce it with an LLM
You are a product engineer. Design a 'like' button micro-interaction by its four parts and then build it: (1) trigger — the user taps; (2) rules — what state changes and any constraints; (3) feedback — the visible/animated response; (4) loops & modes — what happens on repeat, and any long-term state. Build it in React with the Motion library: a heart that fills and gives a quick springy pop on like, returns calmly on unlike. Requirements: a real <button> with aria-pressed reflecting state; visible focus ring; animate only transform/opacity; fully disable motion under prefers-reduced-motion. Label each of the four parts in comments. Return only the component code with imports.
Pitfalls & accessibility
Related
Motion principles
Borrowed from classic animation: timing, anticipation, follow-through, and staging turn a mechanical move into one that reads as intentional.
Jelly button: squash & stretch on press
Make a control feel physical: it squashes when pressed and springs back with a wobble.
Tap & gesture feedback
Touch interfaces lack physical clicks, so a tap needs visible feedback — a ripple and a small press — to confirm the surface felt you.
Further reading
- The four-part model of a micro-interaction, as laid out in the interaction-design literature that named the pattern.
- Your animation library's spring docs, for how stiffness and damping shape the pop you feel in the feedback step.