Micro-animation

Small animation providing feedback on an interaction.

scale · 220ms · a small nudge of feedback, not a full animation

html

<div class="mot-mic-stage">
  <button type="button" class="mot-mic-btn mot-mic-btn--scale" style="--accent:#F5C2E0;">&hearts; Like</button>
  <p class="mot-mic-caption">scale &middot; 220ms &middot; a small nudge of feedback, not a full animation</p>
</div>
<style>
.mot-mic-stage { width: 100%; max-width: 320px; padding: 24px; background: #FAF7F2; border: 1px solid #24143022; border-radius: 12px; font: 13px system-ui, sans-serif; color: #241430aa; text-align: center; }
.mot-mic-btn { position: relative; overflow: hidden; font: 600 14px system-ui, sans-serif; padding: 10px 18px; border-radius: 999px; border: 1.5px solid #24143022; background: #fff; color: #241430; cursor: pointer; }
.mot-mic-caption { margin: 14px 0 0; }
@media (prefers-reduced-motion: no-preference) {
  .mot-mic-btn { transition: transform 220ms ease-out, background 220ms ease-out, box-shadow 220ms ease-out; }
}
.mot-mic-btn--scale:active, .mot-mic-btn--scale.mot-mic-btn--sim { transform: scale(.9); }
.mot-mic-btn--ripple:active, .mot-mic-btn--ripple.mot-mic-btn--sim { box-shadow: 0 0 0 8px var(--accent); }
.mot-mic-btn--colour-flash:active, .mot-mic-btn--colour-flash.mot-mic-btn--sim { background: var(--accent); }
</style>

tailwind

<div class="w-full max-w-[320px] p-6 bg-[#FAF7F2] border border-[#24143022] rounded-xl font-sans text-sm text-[#241430]/70 text-center">
  <button type="button" class="tw-mic tw-mic--scale relative overflow-hidden font-semibold px-4.5 py-2.5 rounded-full border border-[#24143022] bg-white text-[#241430] cursor-pointer" style="--accent:#F5C2E0;">&hearts; Like</button>
  <p class="mt-3.5">scale &middot; 220ms &middot; a small nudge of feedback, not a full animation</p>
</div>
<style>
@media (prefers-reduced-motion: no-preference) {
  .tw-mic { transition: transform 220ms ease-out, background 220ms ease-out, box-shadow 220ms ease-out; }
}
.tw-mic--scale:active, .tw-mic--scale.tw-mic--sim { transform: scale(.9); }
.tw-mic--ripple:active, .tw-mic--ripple.tw-mic--sim { box-shadow: 0 0 0 8px var(--accent); }
.tw-mic--colour-flash:active, .tw-mic--colour-flash.tw-mic--sim { background: var(--accent); }
</style>

react

export function MicroAnimation({
  feedback = "scale",
  simulate = false,
  duration = 220,
  accent = "#F5C2E0",
}) {
  const active = {
    scale: { transform: "scale(.9)" },
    ripple: { boxShadow: `0 0 0 8px ${accent}` },
    "colour-flash": { background: accent },
  }[feedback];
  return (
    <div style={{ width: "100%", maxWidth: 320, padding: 24, background: "#FAF7F2", border: "1px solid #24143022", borderRadius: 12, fontFamily: "system-ui, sans-serif", fontSize: 13, color: "#241430aa", textAlign: "center" }}>
      <button type="button" className="btn" style={{ position: "relative", overflow: "hidden", fontWeight: 600, fontSize: 14, padding: "10px 18px", borderRadius: 999, border: "1.5px solid #24143022", background: "#fff", color: "#241430", cursor: "pointer", ...(simulate ? active : {}) }}>
        &hearts; Like
      </button>
      <p style={{ margin: "14px 0 0" }}>{feedback} &middot; {duration}ms &middot; a small nudge of feedback, not a full animation</p>
      <style>{`
        @media (prefers-reduced-motion: no-preference) {
          .btn { transition: transform ${duration}ms ease-out, background ${duration}ms ease-out, box-shadow ${duration}ms ease-out; }
        }
      `}</style>
    </div>
  );
}