Micro-Interactions
When building interactive UI components, apply these rules to ensure "feel," continuity, and responsiveness.
Core Philosophy
- •Immediate: Response must happen in <100ms.
- •Continuous: Elements should morph and travel, not teleport.
- •Playful: Use physics (springs) over time-based curves for interactive elements.
- •Subtle: Micro-interactions should whisper, not shout.
1. Interaction & Feedback
- •MUST provide immediate visual feedback on
press(active state). - •SHOULD use
scalefor press states.- •Button/Card standard:
scale: 0.98or0.96. - •Icon Button standard:
scale: 0.9.
- •Button/Card standard:
- •SHOULD use
whileTapin Motion oractive:scale-*in Tailwind. - •NEVER block the UI thread during an interaction; trigger the animation and the action optimistically.
- •MUST styling focus states for keyboard users (use
focus-visible).
2. Motion Physics (Framer Motion)
- •SHOULD prefer
springovertweenfor physical interactions (drag, scale, layout). - •Recommended Spring Configs:
- •Snappy (Buttons/Toggles):
{ stiffness: 400, damping: 25 } - •Fluid (Modals/Drawers):
{ stiffness: 300, damping: 30 } - •Bouncy (Notifications):
{ type: "spring", stiffness: 500, damping: 30, mass: 1 }
- •Snappy (Buttons/Toggles):
- •NEVER use "lazy" springs (default stiffness < 100) for UI controls; it feels sluggish.
3. Spatial Continuity
- •MUST use the
layoutprop inmotion/reactwhen an element changes position or size in the document flow. - •MUST use
layoutIdwhen an element logically moves between two different sub-trees (e.g., a list item expanding into a detail view). - •SHOULD use
layout="position"if only the position changes, to avoid distorted scale transforms on children. - •MUST wrap removing items in
<AnimatePresence mode="popLayout">to prevent layout jumps.
4. Entrances & Exits
- •MUST ensure exits are faster than entrances.
- •Entrance:
duration: 0.3sto0.5s(allow eye to track). - •Exit:
duration: 0.15sto0.2s(get out of the way).
- •Entrance:
- •SHOULD use
staggerChildrenfor lists (> 3 items).- •Stagger delay:
0.05s-0.1s(keep it tight).
- •Stagger delay:
- •SHOULD combine
opacity+y(orscale) for standard entrances. Avoidxaxis unless lateral movement is implied.
5. Tailwind & CSS Transitions
- •USE for simple state changes (colors, subtle shadows, opacity).
- •Standard Transition:
transition-all duration-200 ease-out. - •Hover:
hover:bg-opacity-80orhover:brightness-110> changing HSL values manually. - •NEVER transition
heightorwidthwith CSS (causes reflow); use Framer MotionlayoutorResizeObservertechniques if needed.
6. Accessibility
- •MUST respect
prefers-reduced-motion. - •Implementation:
javascript
const shouldReduce = useReducedMotion(); const transition = shouldReduce ? { duration: 0 } : { type: "spring" };
Reference Patterns
The "Rubber Band" Button
jsx
<motion.button
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.95 }}
transition={{ type: "spring", stiffness: 400, damping: 17 }}
>
The "Shared Layout" Tab (The Magic Pill)
jsx
{isSelected && (
<motion.div
layoutId="active-pill"
className="absolute inset-0 bg-black rounded-full"
transition={{ type: "spring", bounce: 0.2, duration: 0.6 }}
/>
)}