GitHub Docs

Motion

Motion in VibeUI is intentional and subtle. Transitions communicate state changes. Animations are never decorative — they carry meaning.


Transition Tokens

Token                Value                                    Use
─────────────────────────────────────────────────────────────────────────────────
--transition-fast    0.15s cubic-bezier(0.4, 0, 0.2, 1)     Hover, focus, button press
--transition-smooth  0.25s cubic-bezier(0.4, 0, 0.2, 1)     Progress bar fill, tab switch
--transition-spring  0.35s cubic-bezier(0.34, 1.56, 0.64, 1) Entrance animations, dialogs

The easing (0.4, 0, 0.2, 1) is Material Design’s “standard” easing — fast out of a state, decelerates into the new one. The spring variant overshoots slightly, communicating elasticity.


When to Animate

Trigger Transition Duration
Button hover/active opacity, transform fast (0.15s)
Button hover glow box-shadow fast (0.15s)
Input focus ring border-color, box-shadow fast (0.15s)
Progress bar fill width smooth (0.25s)
Tab switch background, border-color fast (0.15s)
Modal/drawer open transform, opacity spring (0.35s)
Theme toggle background-color, color smooth (0.25s)
Sidebar resize width smooth (0.25s)

When NOT to Animate

  • Data loading (use a loading indicator, not an animation)
  • List item mount/unmount (adds visual noise in dense panels)
  • Scroll position
  • Error messages (show immediately)

Button Transitions

.panel-btn uses:

transition: opacity var(--transition-fast), background var(--transition-fast);

.btn-primary / .btn-secondary use:

transition: all var(--transition-fast);
/* hover: translateY(-1px) + elevation-2 + glow */
/* active: translateY(0) + elevation-1 */

Progress Bar Animation

All progress bar fills use --transition-smooth:

.progress-bar-fill {
  transition: width var(--transition-smooth);
}

When the value updates in React, the bar animates automatically. No JS needed.


Loading Spinner

The .spin class provides a CSS rotation animation:

<span className="spin" style={{ display: "inline-block", fontSize: 14 }}></span>

// Or with a Lucide icon
<Icon name="loader" size={14} className="spin" />
@keyframes spin {
  to { transform: rotate(360deg); }
}
.spin { animation: spin 1s linear infinite; }

Theme Transition

Global theme changes (body, .header, .sidebar, etc.) use --transition-smooth on background-color, color, and border-color. This is set in App.css globally — panels inherit it automatically.


Reduced Motion

Always respect user preference. Progress bars, loading indicators, and any CSS animation should respect:

@media (prefers-reduced-motion: reduce) {
  .progress-bar-fill { transition: none; }
  .spin { animation: none; }
}

Currently respected at the global level. When adding new CSS animations, add a prefers-reduced-motion override.