Guidelines for using motion purposefully, accessibly, and consistently across Customer.io interfaces.
Motion is a powerful tool that brings our interfaces to life and guides users through their journey. When used thoughtfully, motion reduces cognitive load, provides essential feedback, and adds personality to the Customer.io experience. These guidelines ensure motion is purposeful, accessible, and aligned with our design principles.
Motion in our platform today
The animation system is fragmented across multiple approaches: global CSS keyframes, Ember Animated for complex transitions, Vanilla Extract for CSS-in-JS, and native SVG animations. There's no single unified animation framework, though the Visual Workflow Builder has the most sophisticated centralized configuration via ANIMATION_CONFIG. More here
Every animation must serve a clear function. Motion should guide users, provide feedback, or clarify relationships between elements. It never exists purely for decoration.
Motion should make interfaces feel immediate and alive. User actions should receive instant visual feedback that's both seen and felt.
Animations should be quick enough to feel snappy but slow enough to be perceived. They should enhance workflow, not slow it down.
Motion must work for everyone. Always provide alternatives and respect user preferences for reduced motion.
Customer.io uses two distinct motion styles to match different moments in the user experience:
Use for: Day-to-day tasks, data entry, navigation, and workflow actions
Productive motion is subtle, efficient, and stays out of the way. It creates a sense of responsiveness while helping users focus on completing their tasks.
Characteristics:
Examples: Button states, dropdown menus, toggling settings, data table sorting, revealing additional information
Use for: Important moments, primary actions, celebrations, and system communications
Expressive motion is more visible and enthusiastic. It captures attention during significant moments and adds personality to key interactions.
Characteristics:
Examples: Completing a campaign, successful data import, opening a new feature, important notifications, onboarding celebrations
Easing curves define how motion accelerates and decelerates. Natural motion speeds up quickly and slows down smoothly like objects in the physical world.
When to use: Elements visible from beginning to end of motion
Productive: cubic-bezier(0.2, 0, 0.38, 0.9)
Expressive: cubic-bezier(0.4, 0.14, 0.3, 1)
Examples: Expanding panels, sorting table rows, transforming components
When to use: Elements entering the view
Productive: cubic-bezier(0, 0, 0.38, 0.9)
Expressive: cubic-bezier(0, 0, 0.3, 1)
Examples: Modal appearing, toaster notifications, dropdown opening, tooltip revealing
When to use: Elements leaving the view permanently
Productive: cubic-bezier(0.2, 0, 1, 0.9)
Expressive: cubic-bezier(0.4, 0.14, 1, 1)
Examples: Closing modals, dismissing notifications, removing items
Exception: For elements that stay nearby (like side panels that slide off-screen but remain accessible), use standard easing instead of exit easing to imply they're ready to return.
Duration should be dynamic based on the distance traveled and the size of the animated element. Larger movements take longer; smaller movements are quicker.
| Token | Use Case | Value |
|---|---|---|
duration-fast-01 | Micro-interactions (buttons, toggles) | 70ms |
duration-fast-02 | Micro-interactions (fades) | 110ms |
duration-moderate-01 | Small movements, short distances | 150ms |
duration-moderate-02 | Medium expansion, toasts | 240ms |
duration-slow-01 | Large expansion, important notifications | 400ms |
duration-slow-02 | Background dimming, full-screen transitions | 700ms |
Duration: 70-110ms
Easing: Entrance (productive)
Motion: Subtle scale change or color shift on hover/press
Duration: 150ms
Easing: Entrance (productive)
Motion: Fade in with slight vertical movement
Duration: 240ms
Easing: Entrance (expressive)
Motion: Fade in background overlay, scale up modal with slight upward movement
Duration: 240ms
Easing: Entrance (expressive) on appear, Exit (expressive) on dismiss
Motion: Slide in from edge with fade, slide out on dismiss
Duration: 240-400ms
Easing: Standard (productive)
Motion: Smooth cross-fade or slide between views
The codebase defines reusable CSS keyframe animations in a central stylesheet: animations.scss:1-90
These include:
flash - opacity pulsing effectshake - horizontal shake animationflash-single - single flash effectdrop-fade-below/above - vertical slide + fadeflyout-right - horizontal slide + fadefade-in - simple opacity transitionThe Visual Workflow Builder uses ember-animated for complex component transitions: index.gts:135-146
Animation Configuration: Centralized timing/easing values are defined in ANIMATION_CONFIG: index.gts:1898-1916
This includes configurations for:
Key Animation Patterns:
translateMoveFade with configurable offsets and timing index.gts:1914-1916index.gts:1919-1945index.gts:1985-2010The segment/audience builder uses @vanilla-extract/css for programmatic animations: expanded.css.ts:1-77
Animation approach:
expanded.css.ts:11-12expanded.css.ts:15-53expanded.css.ts:67-68section.gts:317-334index.gts:119-176index.gts:121-134index.css.ts:4-39The Octopus integration uses native SVG animateMotion with dynamic timing: index.gts:43-78
Animation tests use ember-animated/test-support with accelerated playback: actions-test.ts:18-25
Tests wait for animationsSettled() before assertions: favorites-test.ts:109-110
In the separate customerio/hydra repo, there's a React-based help sidebar using Framer Motion with reduced motion support: index.tsx:35-62 This suggests the organization uses different animation libraries across different frontend stacks (Ember vs React).
The animation system is fragmented across multiple approaches: global CSS keyframes, Ember Animated for complex transitions, Vanilla Extract for CSS-in-JS, and native SVG animations. There's no single unified animation framework, though the Visual Workflow Builder has the most sophisticated centralized configuration via ANIMATION_CONFIG.