Coconut Design System v3.11.0
home Home

Motion

Animation and transition guidelines that create fluid, purposeful motion. Every animation serves to orient users, provide feedback, or establish spatial relationships.

Transitions

Standard transition applied to most interactive elements: all 0.2s ease. Individual properties may use custom durations for more refined behavior.

Transition property reference
PropertyDurationEasingUsage
background 0.3s ease Theme switching, hover state backgrounds
color 0.3s ease Theme switching, link/text color changes
transform 0.2s ease Card hover lift, button press, scale effects
box-shadow 0.2s ease Elevation changes on hover, focus rings
opacity 0.15s ease Fade in/out, tooltip visibility, drag handles
border-color 0.15s ease Input focus states, card hover borders, theme transitions
/* Standard transition — most interactive elements */ transition: all 0.2s ease; /* Theme transition — slower for comfortable switch */ transition: background 0.3s ease, color 0.3s ease; /* Micro-interaction — quick response */ transition: opacity 0.15s ease, border-color 0.15s ease;

Animations

Keyframe animations used throughout the design system. Each serves a specific purpose.

glassIn — 0.35s ease

Cards and content blocks appear by sliding up 8px with a subtle scale from 0.98. The primary entry animation for dashboard content.

Card Title
Content appears with glassIn
@keyframes glassIn { from { opacity: 0; transform: translateY(8px) scale(0.98); } to { opacity: 1; transform: translateY(0) scale(1); } } /* Usage */ animation: glassIn 0.35s ease both;
fadeIn — 0.3s ease

Simple opacity transition from 0 to 1. Used for overlays, tooltips, and supplementary content.

Faded in content
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } animation: fadeIn 0.3s ease both;
dotPulse — 2s ease-in-out infinite

Status badge dots pulse between scale 1 and 1.3 with opacity changes. Conveys a live, active state.

Active
Pending
Error
@keyframes dotPulse { 0%, 100% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.3); opacity: 0.7; } } .badge-dot { animation: dotPulse 2s ease-in-out infinite; }
bellPulse — 1.5s ease-in-out infinite

Notification bell icon scales up to 1.15 with an expanding box-shadow ring. Draws attention to unread notifications.

notifications
The bell pulses continuously when there are unread critical notifications requiring attention.
@keyframes bellPulse { 0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(186,26,26,0.5); } 50% { transform: scale(1.15); box-shadow: 0 0 0 6px rgba(186,26,26,0); } }
skeleton-pulse — 1.5s ease-in-out infinite

Loading placeholder that oscillates opacity between 0.6 and 0.3. Used for content skeletons while data loads.

@keyframes skeleton-pulse { 0% { opacity: 0.6; } 50% { opacity: 0.3; } 100% { opacity: 0.6; } } .skeleton-line { animation: skeleton-pulse 1.5s ease-in-out infinite; }
toastSlideIn / toastSlideOut — 0.3s ease

Toast notifications slide in from the right edge and slide out the same direction when dismissed.

info
Notification
Slides in from right
@keyframes toastSlideIn { from { opacity: 0; transform: translateX(100%); } to { opacity: 1; transform: translateX(0); } } @keyframes toastSlideOut { from { opacity: 1; transform: translateX(0); } to { opacity: 0; transform: translateX(100%); } }
spin — continuous rotation

Simple 360-degree rotation for loading spinners. Duration is typically 1s with linear easing.

Default (1s)
Fast (0.6s)
Slow (2s)
@keyframes spin { to { transform: rotate(360deg); } } animation: spin 1s linear infinite;

Staggered Entry

Cards use incrementing animation-delay values to create a cascading entrance. Each subsequent card appears 30ms after the previous one.

Live staggered grid (click replay to see the cascade)
delay: 0.03s
1
delay: 0.06s
2
delay: 0.09s
3
delay: 0.12s
4
delay: 0.15s
5
delay: 0.18s
6
delay: 0.21s
7
delay: 0.24s
8
/* Staggered entry — 30ms increment per card */ .card { animation: glassIn 0.35s ease both; } .card:nth-child(1) { animation-delay: 0.03s; } .card:nth-child(2) { animation-delay: 0.06s; } .card:nth-child(3) { animation-delay: 0.09s; } .card:nth-child(4) { animation-delay: 0.12s; } /* ... continue incrementing by 0.03s */

Hover States

Interactive elements provide visual feedback on hover through transform, shadow, and border changes. Hover over each element below to see the effect.

Card hover: translateY(-2px) scale(1.005)
METRIC
Server Uptime
99.97%
.card:hover { transform: translateY(-2px) scale(1.005); box-shadow: var(--shadow-lg); }
Inline row hover: translateY(-1px)
cloud
Cloud Storage
250 GB used
Active
.inline-row:hover { transform: translateY(-1px); box-shadow: var(--shadow-md); border-color: var(--outline-variant); }
Button hover: box-shadow change
.btn-blue:hover { background: var(--accent-dark); box-shadow: var(--shadow); }
Widget hover: translateY(-1px)
Widget
1,247
+12.5%
.widget:hover { transform: translateY(-1px); box-shadow: 0 3px 8px rgba(0,0,0,0.12); }

Easing Curves

Two easing functions are used throughout the system. The default ease for most interactions, and a Material Design cubic-bezier for panel transitions.

ease (default) — CSS built-in

Used for buttons, cards, badges, toggles, and all standard hover/active states. Equivalent to cubic-bezier(0.25, 0.1, 0.25, 1.0).

ease — cubic-bezier(0.25, 0.1, 0.25, 1.0)
cubic-bezier(0.4, 0, 0.2, 1) — Material decelerate

Used for sidebar panel slide transitions. Provides a quick start with a gentle deceleration, creating a natural-feeling entrance/exit.

cubic-bezier(0.4, 0, 0.2, 1) — sidebar / panel slide
/* Default easing — all interactive elements */ transition: all 0.2s ease; /* Material decelerate — sidebar panel slide */ .docs-sidebar { transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1); } /* Linear — continuous animations (spinners) */ animation: spin 1s linear infinite;

Reduced Motion

Respect user preferences for reduced motion. When the prefers-reduced-motion media query matches, animations and transitions should be minimized or removed entirely.

Implementation guidelines
check_circle
Remove all transform-based animations
glassIn, hover lifts, scale effects, slide transitions
check_circle
Reduce transition durations to near-zero
Use 0.01s instead of 0s to preserve state change callbacks
check_circle
Keep essential opacity changes
Instant opacity transitions are acceptable for show/hide
warning
Stop infinite animations
dotPulse, bellPulse, skeleton-pulse, spin should pause or stop
@media (prefers-reduced-motion: reduce) { /* Remove all animations */ *, *::before, *::after { animation-duration: 0.01s !important; animation-iteration-count: 1 !important; transition-duration: 0.01s !important; } /* Stop infinite pulsing animations */ .badge-dot { animation: none; } .skeleton-line { animation: none; opacity: 0.4; } /* Remove hover transforms */ .card:hover, .inline-row:hover, .widget:hover { transform: none; } }
info Accessibility note: Always test your implementation with motion preferences enabled. On macOS, go to System Settings > Accessibility > Display > Reduce Motion. On Windows, Settings > Ease of Access > Display > Show animations.