Introduction
Micro-interactions are small functional animations responding to user actions — a button depressing on click, a toggle sliding, a form field shaking on error. They make the difference between an interface that feels dead and one that feels alive.
Good micro-interactions are nearly invisible. They feel so natural that users only notice when they're missing.
This guide covers the most important micro-interactions with production-ready code.
Key Concepts
The Four Parts
Every micro-interaction has: 1) Trigger (user action), 2) Rules (what happens), 3) Feedback (visual response), 4) Loops/Modes (repeat behavior). Design all four.
Feedback Hierarchy
Match intensity to importance. Hover: subtle color. Click: scale + color. Destructive: color + shake. Error: persistent until resolved.
Practical Examples
1. Button States
.button {
transition: background 0.15s ease, transform 0.1s ease;
}
.button:hover { background: #2563eb; }
.button:active { transform: scale(0.97); }
.button:focus-visible { outline: 2px solid #3b82f6; outline-offset: 2px; }
.button.loading { pointer-events: none; opacity: 0.7; }
.button.loading::after {
content: ''; width: 16px; height: 16px;
border: 2px solid transparent; border-top-color: white;
border-radius: 50%; animation: spin 0.6s linear infinite;
margin-left: 0.5rem; display: inline-block;
}
2. Toggle Switch
.toggle {
width: 48px; height: 28px; background: #d1d5db;
border-radius: 14px; position: relative;
transition: background 0.2s ease;
}
.toggle.active { background: #3b82f6; }
.toggle::after {
content: ''; width: 24px; height: 24px;
background: white; border-radius: 50%;
position: absolute; top: 2px; left: 2px;
transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.toggle.active::after { transform: translateX(20px); }
3. Form Validation Shake
@keyframes shake {
0%, 100% { transform: translateX(0); }
20% { transform: translateX(-6px); }
40% { transform: translateX(6px); }
60% { transform: translateX(-4px); }
80% { transform: translateX(4px); }
}
.input.error { animation: shake 0.4s ease; border-color: #ef4444; }
4. Skeleton Loading
@keyframes shimmer {
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
}
.skeleton {
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
border-radius: 4px;
}
5. Tooltip Entrance
.tooltip {
opacity: 0; transform: translateY(4px);
transition: opacity 0.15s ease, transform 0.15s ease;
pointer-events: none;
}
.trigger:hover .tooltip {
opacity: 1; transform: translateY(0);
}
Best Practices
- ✅ Keep micro-interactions under 300ms
- ✅ Use spring easing for physical interactions (toggles, drags)
- ✅ Provide immediate visual feedback for every user action
- ✅ Design error states that persist until resolved
- ✅ Test on touch devices — hover states don't apply
- ❌ Don't make micro-interactions blocking
- ❌ Don't overdo it — subtlety is key
Common Pitfalls
- 🚫 No hover/focus states — interface feels unresponsive
- 🚫 Same animation for all states — differentiate actions by importance
- 🚫 Forgetting keyboard focus styles
- 🚫 Animations that prevent rapid clicking