micro-interactions — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited micro-interactions (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Motion should confirm action and orient the user — not decorate. A tap that doesn't respond feels broken; a page that teleports feels disorienting. This skill covers click/tap micro-feedback and view transitions in React apps with compositor-safe, accessible motion.
Pair with [[ui-craft]] for interaction quality and states, [[react-patterns]] for Client boundaries and perf, [[accessibility]] for reduced-motion and focus, [[browser-checks]] to verify in a real browser, and [[perf-budget]] if animations run on hot paths or large lists.
Run the micro-interactions checklist before merge.
Skip as primary skill when there is no interactive UI (pure API, batch jobs). Not a substitute for [[ui-craft]] — motion sits on top of correct structure and states.
| Situation | Lead skill |
|---|---|
| General UI build + states | [[ui-craft]] → micro-interactions for motion |
| React perf / RSC boundaries | [[react-patterns]] |
| WCAG, focus, screen readers | [[accessibility]] |
| Click feedback + page transition on same feature | micro-interactions |
Work in order. Spec motion before sprinkling CSS.
For each interactive surface, write one line:
If you cannot state the purpose, skip the animation.
Before any implementation:
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}Or gate motion in JS:
const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;Rules:
Prefer CSS-first on the interactive element itself — no extra libraries for a button press.
Do:
:active or data-pressed with transform: scale(0.97) and transition: transform 120ms ease-out:hover only on devices that support hover (@media (hover: hover))transition on transform and opacity only (compositor-friendly)Don't:
width, height, top, left, margin, or box-shadow spread on every click (layout/paint cost).button {
transition: transform 120ms ease-out, opacity 120ms ease-out;
}
.button:active {
transform: scale(0.97);
}
@media (hover: hover) {
.button:hover {
opacity: 0.9;
}
}For loading after click: disable + spinner or progress — see [[ui-craft]] submit feedback.
Pick one approach per navigation pattern; don't mix APIs on the same route without reason.
| Pattern | Approach |
|---|---|
| Full page / route change (App Router) | View Transitions API via framework support or document.startViewTransition |
| Tab or segmented control | CSS cross-fade between panels; optional view-transition-name on active tab |
| Modal / drawer | Enter/exit on overlay + panel (transform + opacity); trap focus ([[accessibility]]) |
| List → detail shared element | Named view-transition-name on thumbnail/title in both views |
View Transitions API (browser-native):
function navigate(updateDOM) {
if (!document.startViewTransition) {
updateDOM();
return;
}
document.startViewTransition(() => updateDOM());
}In React, call startViewTransition around the state update that swaps DOM (route content, tab panel, modal body). Assign stable view-transition-name only to elements that should morph — one name per logical shared element.
Next.js App Router: enable view transitions in framework config when available; use <Link> with view transition support rather than hand-rolling per link. Fall back to instant navigation when API unsupported.
React `<ViewTransition>` (when available in your React version): wrap the conditional branch that changes on navigation; treat as experimental — verify bundle and behavior in target browsers.
Avoid by default: pulling in Framer Motion / Motion for every button — use only if the project already standardizes on it and bundle budget allows ([[perf-budget]]).
on the document swap after navigation
| Type | Duration | Easing |
|---|---|---|
| Press feedback | 80–150ms | ease-out |
| Hover hint | 150–200ms | ease-out |
| View enter/exit | 200–350ms | ease-in-out or custom cubic-bezier |
| Stagger (lists) | ≤30ms between items | cap total stagger |
Before merge ([[browser-checks]]):
:hover stuck states; touch feedback worksawaits animation before side effect:hover styles on touch-only devices with no :active fallbackprefers-reduced-motion not handled'use client' on whole page for one button scale effectview-transition-name on multiple elements in the same viewprefers-reduced-motion respected — instant or minimal alternative@media (hover: hover) where needed~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.