Back to skills
SKILL.md
Micro Interaction
ASecurityUse when designing and engineering interactive component micro-motion, tactile button feedback, spring toggles, draw-on checkboxes, toasts, drawer gestures, and shared-element transitions.
- 5 stars
- 0 votes
- 0 copies
- 0 views
- Added September 27, 2026
Works with
Security analysis
100/100npx -y skills add Harmitx7/tribunal-kit --skill micro-interaction --agent claude-codeAre you the author of Micro Interaction?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/harmitx7-micro-interaction-tribunal-kit)---
name: micro-interaction
description: "Use when designing and engineering interactive component micro-motion, tactile button feedback, spring toggles, draw-on checkboxes, toasts, drawer gestures, and shared-element transitions."
version: 5.0.0
last-updated: 2026-09-13
skills:
- delight
- better-ui
- 60fps-animation
- review-animations
tools: Read, Grep, Glob, Bash, Edit, Write
scripts-binding:
- .agent/scripts/lint_runner.js
- .agent/scripts/verify_all.js
---
# Micro-Interaction — Tactile Component Physics & Interactive State Synthesis
---
## 🛠️ Technical Architecture & Reference Recipes
Micro-interactions bridge intention and confirmation. When a button compresses beneath a pointer or a toggle thumb squashes as it slides across the track, digital interfaces cross the chasm from static abstractions to physical, responsive objects. Poor micro-interactions feel floaty, sluggish (>250ms), or introduce layout displacement. Master-grade micro-interactions operate under a strict sub-180ms execution budget, maintain volume mass conservation, anchor transform origins directly to interaction loci, and fire subtle tactile feedback.
---
---
---
---
## 🛠️ Technical Architecture & Reference Recipes
### 1. The Micro-Interaction Timing & Easing Matrix
| Component | Target Duration | Recommended Curve / Physics | Perceived Feel |
| :--------------------------- | :-------------- | :-------------------------------------- | :----------------------------------- |
| **Button Press (`:active`)** | 80ms–120ms | `cubic-bezier(0.2, 0, 0, 1)` | Crisp, immediate tactile resistance |
| **Toggle Switch** | 160ms–200ms | `spring(stiffness: 420, damping: 26)` | Snappy with slight organic overshoot |
| **Checkbox Tick** | 140ms–180ms | `stroke-dashoffset` linear deceleration | Decisive, pencil-drawn precision |
| **Toast Pop-In** | 180ms–240ms | `cubic-bezier(0.16, 1, 0.3, 1)` | Smooth magnetic arrival |
| **Popover / Dropdown** | 140ms–180ms | `scale(0.96) -> 1` + origin anchoring | Anchored physical unfold |
---
### 2. Five Production-Grade Implementation Recipes
#### Recipe 1: Tactile Elastic Button Press (React + Framer Motion)
```tsx
import React from 'react';
import { motion } from 'framer-motion';
export function TactileButton({
children,
onClick,
className = '',
}: {
children: React.ReactNode;
onClick?: () => void;
className?: string;
}) {
const handleClick = () => {
if (typeof window !== 'undefined' && 'vibrate' in navigator) {
navigator.vibrate(8); // Subtle 8ms tactile micro-pulse
}
onClick?.();
};
return (
<motion.button
type="button"
onClick={handleClick}
whileHover={{ scale: 1.02, y: -1 }}
whileTap={{ scale: 0.96, y: 1 }}
transition={{ type: 'spring', stiffness: 500, damping: 30 }}
className={`inline-flex items-center justify-center px-4 py-2 font-medium text-sm rounded-xl bg-neutral-900 dark:bg-white text-white dark:text-neutral-900 shadow-sm hover:shadow active:shadow-inner touch-manipulation focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-500 ${className}`}
>
{children}
</motion.button>
);
}
```
---
#### Recipe 2: Organic Squash-and-Stretch Toggle Switch
```tsx
import React from 'react';
import { motion } from 'framer-motion';
export function ElasticToggle({
checked,
onChange,
label,
}: {
checked: boolean;
onChange: (checked: boolean) => void;
label: string;
}) {
return (
<label className="inline-flex items-center gap-3 cursor-pointer select-none">
<span className="text-sm font-medium text-neutral-700 dark:text-neutral-300">{label}</span>
<button
type="button"
role="switch"
aria-checked={checked}
onClick={() => onChange(!checked)}
className={`relative w-12 h-7 rounded-full p-0.5 transition-colors duration-200 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-500 ${
checked ? 'bg-indigo-600' : 'bg-neutral-300 dark:bg-neutral-700'
}`}
>
<motion.div
animate={{
x: checked ? 20 : 0,
scaleX: [1, 1.25, 0.95, 1], // Squash as it pushes off, stretches in transit, snaps into place
scaleY: [1, 0.85, 1.05, 1],
}}
transition={{
x: { type: 'spring', stiffness: 480, damping: 28 },
scaleX: { duration: 0.22 },
scaleY: { duration: 0.22 },
}}
className="w-6 h-6 rounded-full bg-white shadow-md"
/>
</button>
</label>
);
}
```
---
#### Recipe 3: Animated SVG Draw-On Checkbox
```tsx
import React from 'react';
import { motion } from 'framer-motion';
export function DrawOnCheckbox({
checked,
onChange,
label,
}: {
checked: boolean;
onChange: (c: boolean) => void;
label: string;
}) {
return (
<label className="inline-flex items-center gap-3 cursor-pointer select-none">
<button
type="button"
role="checkbox"
aria-checked={checked}
onClick={() => onChange(!checked)}
className={`w-5 h-5 rounded-md border flex items-center justify-center transition-colors duration-150 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-500 ${
checked
? 'bg-indigo-600 border-indigo-600 text-white'
: 'border-neutral-400 dark:border-neutral-600 bg-white dark:bg-neutral-900'
}`}
>
<svg
viewBox="0 0 16 16"
className="w-3.5 h-3.5 stroke-current fill-none stroke-[2.4] stroke-linecap-round stroke-linejoin-round"
>
<motion.path
d="M 3.5 8.5 L 6.5 11.5 L 12.5 4.5"
initial={false}
animate={{ pathLength: checked ? 1 : 0, opacity: checked ? 1 : 0 }}
transition={{ duration: 0.16, ease: [0.16, 1, 0.3, 1] }}
/>
</svg>
</button>
<span className="text-sm text-neutral-800 dark:text-neutral-200">{label}</span>
</label>
);
}
```
---
#### Recipe 4: Dynamic Directional Toast with Spring Layout
```tsx
import React from 'react';
import { motion, AnimatePresence } from 'framer-motion';
interface ToastProps {
id: string;
message: string;
onDismiss: (id: string) => void;
}
export function ToastContainer({
toasts,
onDismiss,
}: {
toasts: ToastProps[];
onDismiss: (id: string) => void;
}) {
return (
<div className="fixed bottom-6 right-6 z-50 flex flex-col gap-2 pointer-events-none">
<AnimatePresence mode="popLayout">
{toasts.map(toast => (
<motion.div
key={toast.id}
layout
initial={{ opacity: 0, y: 24, scale: 0.94 }}
animate={{ opacity: 1, y: 0, scale: 1 }}
exit={{ opacity: 0, scale: 0.92, transition: { duration: 0.14 } }}
transition={{ type: 'spring', stiffness: 420, damping: 28 }}
className="pointer-events-auto flex items-center justify-between min-w-[280px] p-4 rounded-xl bg-neutral-900 text-white shadow-xl border border-neutral-800"
>
<span className="text-sm font-medium">{toast.message}</span>
<button
type="button"
onClick={() => onDismiss(toast.id)}
className="ml-3 text-xs text-neutral-400 hover:text-white transition-colors"
>
Dismiss
</button>
</motion.div>
))}
</AnimatePresence>
</div>
);
}
```
---
#### Recipe 5: Context-Aware Popover with Dynamic `transform-origin`
```css
/* Popover Unfold from Anchor Coordinate */
.popover-bubble {
transform-origin: var(--radix-popover-content-transform-origin, top center);
animation: popover-unfold 160ms cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
@keyframes popover-unfold {
from {
opacity: 0;
transform: scale(0.94) translateY(-4px);
}
to {
opacity: 1;
transform: scale(1) translateY(0);
}
}
```
Attribution
Comments
Loading comments…