Skip to content

FRD-030: Motion Coverage Per Component

FieldValue
OwnerDavid Holmes
StatusDraft
Last Updated2026-05-26
Target Releasev2.0.0
TypeRefactor
SizeM
PriorityP1 — Component Improvement

Document Summary

Audit every animated component in the design system and document its motion preset, reduced-motion behavior, and duration. Create reusable “motion recipes” that standardize common animation patterns (overlay enter/exit, accordion expand, toast slide, skeleton pulse). Fill the gap between the robust token layer in src/styles/motion.css and the undocumented per-component motion behavior. Reference ADR-002 and ADR-004 for motion governance.


Introduction

Overview

The design system defines motion tokens (--motion-instant through --motion-slow, easing curves, reduced-motion overrides) in src/styles/motion.css and applies them via Tailwind utilities (duration-fast, ease-standard, etc.). However, there is no component-level documentation of which motion preset each component uses, what happens under prefers-reduced-motion: reduce, or how long each animation actually lasts. This makes it difficult for developers to predict behavior, for designers to specify motion, and for accessibility auditors to verify compliance.

Goals

  • Audit all animated components and catalog their motion behavior (preset, duration, easing, reduced-motion fallback).
  • Create a “motion recipes” system — named, reusable CSS utility classes for common animation patterns (e.g., motion-overlay-enter, motion-accordion-expand, motion-toast-slide).
  • Ensure every animated component maps to a documented motion recipe.
  • Verify that all components degrade gracefully under prefers-reduced-motion: reduce.
  • Publish a Storybook docs page with an interactive motion catalog.

Non-Goals

  • Changing any existing animation timing (unless broken under reduced-motion).
  • Adding animation to components that are currently static.
  • Integrating a JavaScript animation library (Framer Motion, React Spring); CSS-only approach.

Scope

In Scope

ItemDescription
Motion auditCatalog every component with animation: what token it uses, what triggers it, and what reduced-motion does.
Motion recipesNamed CSS utility classes in src/styles/motion.css for overlay enter/exit, accordion expand/collapse, toast enter/exit, skeleton pulse, fade in/out, scale in/out.
Per-component documentationEach animated component’s Storybook docs page gets a “Motion” section documenting its animation behavior.
Reduced-motion verificationTest every animated component with prefers-reduced-motion: reduce to ensure graceful degradation.
Motion catalog pageA Storybook docs page listing all motion recipes with interactive previews.
ADR-002 / ADR-004 alignmentVerify all motion choices align with existing ADR guidance.

Out of Scope

ItemReason
New animationsOnly documenting and standardizing existing motion; not adding animation to static components.
JavaScript animation librariesCSS transitions and keyframes only; no new runtime dependencies.
Page-level transitionsRoute transitions are an application concern, not a component concern.

Users and Pain Points

UserPain Point
Developers extending componentsCannot determine which motion token a component uses without reading the source.
Designers specifying motionNo reference catalog to point to when specifying animation timing in design specs.
Accessibility auditorsCannot verify reduced-motion compliance without manual testing of each component.
LLM agents building componentsNo recipe system to reference; agents pick arbitrary durations or skip animation entirely.

Definitions

TermDefinition
Motion presetA combination of duration token, easing curve, and animation properties (e.g., opacity + transform).
Motion recipeA named, reusable CSS class applying a specific motion preset to a specific interaction pattern (enter, exit, expand).
Reduced-motionThe prefers-reduced-motion: reduce media query, indicating the user prefers minimal animation.
Duration tokenA CSS custom property from motion.css (e.g., --motion-standard: 160ms).
Easing curveA CSS transition-timing-function or animation-timing-function (e.g., --ease-standard).

Current State

  • motion.css (src/styles/motion.css): Defines 6 duration tokens (instant through slow), 4 easing curves, and a prefers-reduced-motion override block that halves all durations and disables repeating animations.
  • Tailwind utilities: duration-fast, duration-standard, ease-standard, etc. are used in component class strings.
  • Existing motion utilities: .motion-control, .motion-control-emphasis, .motion-indicator, .motion-overlay-enter, .motion-toast-enter, .motion-toast-exit classes exist but are not documented.
  • Per-component docs: No component Storybook page documents its motion behavior.
  • ADR-002: Governs temporal conventions. ADR-004: Governs motion design principles.
  • Gap: No catalog mapping components to motion recipes; no reduced-motion verification matrix.

Proposed Solution

Phase 1: Audit

Systematically review every component with CSS transitions or keyframe animations. For each, record:

  • Which duration token is used.
  • Which easing curve is used.
  • What CSS properties are animated (opacity, transform, height, etc.).
  • What triggers the animation (mount, state change, hover, focus).
  • What happens under prefers-reduced-motion: reduce.

Output: A structured audit table (added to the motion catalog Storybook page).

Phase 2: Standardize into recipes

Group the audit findings into recipe categories:

RecipeTokenEasingPropertiesReduced-motion
motion-overlay-enter--motion-overlay (220ms)--ease-standardopacity, transform (scale)Instant opacity, no scale
motion-overlay-exit--motion-overlay--ease-exitopacity, transform (scale)Instant opacity, no scale
motion-accordion-expand--motion-standard (160ms)--ease-standardheight, opacityInstant toggle
motion-toast-enter--motion-emphasis (200ms)--ease-standardopacity, translateYInstant opacity
motion-toast-exit--motion-fast (120ms)--ease-exitopacity, translateYInstant opacity
motion-fade-in--motion-fast--ease-standardopacityInstant opacity
motion-skeleton-pulse--motion-slow (280ms)--ease-linearopacity (keyframe loop)Static opacity 0.5
motion-control-hover--motion-fast--ease-standardbackground-color, border-colorInstant

Each recipe is a CSS class in motion.css that encapsulates the full animation behavior including reduced-motion fallback.

Phase 3: Apply and document

  • Ensure each animated component uses the appropriate recipe class (replacing ad-hoc inline duration/easing).
  • Add a “Motion” section to each component’s Storybook docs page.
  • Create the interactive motion catalog docs page.

Requirements

Requirement Priorities

  • Must Have: Motion audit, motion recipes in CSS, reduced-motion verification.
  • Should Have: Per-component Storybook motion docs, motion catalog page.
  • Could Have: Interactive recipe playground with duration/easing sliders.

Functional Requirements

IDRequirementPriority
FR-01Complete motion audit covering all animated components in the design system.Must
FR-02Define motion recipes as CSS utility classes in src/styles/motion.css.Must
FR-03Each recipe includes both standard and reduced-motion behavior in a single class.Must
FR-04Refactor components to use recipe classes instead of ad-hoc inline transitions where they diverge.Should
FR-05Each animated component’s Storybook docs page includes a “Motion” section.Should
FR-06A Storybook “Motion Catalog” docs page lists all recipes with live previews.Should
FR-07All components pass reduced-motion verification (no animation > 100ms under prefers-reduced-motion: reduce).Must

Non-Functional Requirements

IDRequirementTarget
NFR-01No new runtime dependencies.CSS-only implementation.
NFR-02No visual regression in existing animation behavior.Recipes must match current timings exactly.
NFR-03motion.css bundle size increase< 1 KB gzipped for all new recipe classes.
NFR-04Reduced-motion max animation durationAll animations ≤ 100ms under prefers-reduced-motion: reduce.

API/Interface Requirements

Motion recipe CSS classes

/* Example recipe structure */
.motion-overlay-enter {
animation: overlay-enter var(--motion-overlay) var(--ease-standard) both;
}
@keyframes overlay-enter {
from { opacity: 0; transform: scale(var(--motion-overlay-scale-start)); }
to { opacity: 1; transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
.motion-overlay-enter {
animation-duration: var(--motion-instant);
animation-name: fade-in;
}
}

Per-component doc format

Each component’s Storybook docs page “Motion” section includes:

## Motion
| Trigger | Recipe | Duration | Reduced-motion |
|---|---|---|---|
| Popover open | `motion-overlay-enter` | 220ms | 40ms fade |
| Popover close | `motion-overlay-exit` | 220ms | 40ms fade |

Accessibility Requirements

IDRequirement
A11Y-01All animations respect prefers-reduced-motion: reduce; no animation exceeds 100ms in reduced mode.
A11Y-02No animation is the sole indicator of a state change; visual state (color, icon, position) always accompanies motion.
A11Y-03Looping animations (skeleton pulse) stop or become static under prefers-reduced-motion: reduce.
A11Y-04Motion catalog page includes a toggle to preview all recipes in reduced-motion mode.

Content and Documentation Requirements

IDRequirement
DOC-01Motion catalog Storybook page listing all recipes with live interactive previews.
DOC-02Per-component “Motion” section in each animated component’s Storybook docs.
DOC-03Migration guide for teams using ad-hoc inline transitions to adopt recipe classes.
DOC-04Reference link to ADR-002 and ADR-004 from the motion catalog page.

Dependencies

DependencyTypeRisk
src/styles/motion.cssInternalLow — extending existing file.
ADR-002, ADR-004InternalLow — alignment check, no changes to ADRs.
All animated componentsInternalMedium — multiple files audited, but changes are CSS class swaps.

Risks and Tradeoffs

RiskLikelihoodImpactMitigation
Recipe classes don’t cover every bespoke animation in the systemMediumLowRecipes cover the 80% case; edge cases document their custom behavior inline.
Refactoring to recipe classes introduces visual regressionMediumMediumCompare before/after with Chromatic/Percy; recipes match existing timings.
motion.css grows unwieldy with too many recipesLowLowCap at 10-12 recipes; complex animations compose multiple recipes.

Open Questions

#QuestionOwnerStatus
OQ-01Should the motion catalog page include a reduced-motion simulation toggle or rely on OS-level settings?David HolmesOpen
OQ-02Should motion recipes use CSS @layer for specificity isolation?David HolmesOpen
OQ-03Should there be a “motion-none” class for explicitly disabling animation on a component?David HolmesOpen

Acceptance Criteria

#Criterion
AC-01A motion audit table exists documenting every animated component’s preset, duration, easing, and reduced-motion behavior.
AC-02Motion recipe CSS classes are defined in src/styles/motion.css covering overlay, accordion, toast, fade, skeleton, and control-hover patterns.
AC-03Each recipe includes reduced-motion fallback within the same class.
AC-04All animated components use recipe classes (or document their custom behavior if they deviate).
AC-05All components pass reduced-motion verification (no animation > 100ms).
AC-06A Motion Catalog Storybook docs page exists with live recipe previews.
AC-07pnpm typecheck and pnpm vitest run --project unit pass with zero errors.
AC-08pnpm build-storybook succeeds without warnings related to motion classes.

LLM Handoff Instructions

When implementing this FRD:

  1. Start with the audit. Use rg to find all uses of duration-, ease-, transition-, animation-, and @keyframes across src/. Build a table mapping each component to its motion behavior.
  2. Then define recipes in src/styles/motion.css. Group audit findings into recipe categories. Each recipe is a CSS class with the full animation + reduced-motion fallback. Place them in the @layer utilities block alongside existing motion utilities.
  3. Then refactor components to use recipe classes where they currently use ad-hoc inline transition classes. This should be a class swap, not a behavior change.
  4. Then verify reduced-motion by running Storybook with prefers-reduced-motion: reduce emulated (Chrome DevTools > Rendering). Check that no animation exceeds 100ms.
  5. Then document — add “Motion” sections to each animated component’s Storybook docs page, and create the Motion Catalog page.

Key files:

  • src/styles/motion.css — token and recipe definitions.
  • ADR-002 and ADR-004 — governance for motion decisions.
  • All component .tsx files with transition/animation classes.

Decision Log

DateDecisionRationale
2026-05-26CSS-only recipes; no JavaScript animation library.Keeps bundle small; CSS transitions cover all current use cases.
2026-05-26Recipes include reduced-motion fallback in the same class (not a separate override).Single class application ensures reduced-motion is never forgotten.
2026-05-26Audit-first approach before defining recipes.Recipes should match existing behavior, not impose new timings.

Document History

VersionDateAuthorChanges
0.12026-05-26David HolmesInitial draft.