Motion
Timing, easing, and animation tokens for consistent micro-interactions.
Overview
Byteion defines motion tokens for transition durations, easing curves, and 16 named keyframe animations. Every interactive component uses these tokens for hover, focus, open, close, loading, validation, selection, and feedback interactions.
Motion is used across SaaS dashboards, admin panels, ERP and POS tools, ecommerce back offices, internal tools, forms, modals, dropdowns, toasts, tabs, skeleton loaders, and command palettes. Transitions are intentionally subtle — Byteion is designed for data-heavy product interfaces where clarity matters more than flourish.
When to use motion
- Use fast transitions for hover, focus, toggles, and small state changes.
- Use default transitions for buttons, inputs, tabs, dropdowns, and tooltips.
- Use slow transitions for overlays, modals, drawers, and large panels.
- Use
animate-shimmerfor loading placeholders and skeleton screens. - Use
animate-shakeonly for validation errors or failed actions. - Use
animate-check-poporanimate-scale-springfor confirmation or selection feedback.
When not to use motion
- Do not animate every card, row, or table cell in dense dashboards — it creates visual noise.
- Do not delay critical data visibility with slow entrance animations.
- Do not use spring or bouncy animations for serious admin workflows — they feel playful, not trustworthy.
- Do not use motion as the only feedback for errors or success — always pair with text and colour.
- Do not repeatedly shake inputs after every keystroke — one shake on submission is enough.
- Do not use decorative motion that competes with task completion — motion should serve the interaction.
Duration
Duration tokens control transition speed. The default transition applies when no explicit duration-* class is used:
| Token | Tailwind class | Value | Use case |
|---|---|---|---|
| instant | duration-instant | 0ms | Immediate state changes, no visible transition |
| fast | duration-fast | 120ms | Micro-interactions, toggles |
| normal (default) | duration-normal | 200ms | Default transitions — buttons, inputs, tabs |
| slow | duration-slow | 320ms | Overlay open/close, slide, drawer |
| slower | duration-slower | 500ms | Large panel transitions, page-level entrances |
Easing
Easing tokens control the acceleration curve of transitions and animations. The default easing applies when no explicit ease-* class is used:
| Token | Tailwind class | Curve | Best for | Avoid for |
|---|---|---|---|---|
| default | ease-default | cubic-bezier(0.4, 0, 0.2, 1) | General UI transitions | Expressive animations |
| out-soft | ease-out-soft | cubic-bezier(0.22, 1, 0.36, 1) | Entrances, overlays, smooth deceleration | Error feedback, alerts |
| spring | ease-spring | cubic-bezier(0.34, 1.56, 0.64, 1) | Celebratory or selection feedback | Dense enterprise tables, admin workflows |
| in-soft | ease-in-soft | cubic-bezier(0.55, 0, 0.68, 0.06) | Exit transitions, dismissals | Entrance or reveal animations |
| out | ease-out | cubic-bezier(0, 0, 0.2, 1) | Clean exits, quick dismissals | Emphasis or spring-like reveals |
| in | ease-in | cubic-bezier(0.4, 0, 1, 1) | Fast entrances that finish at full speed | Overlay reveals, soft transitions |
| in-out | ease-in-out | cubic-bezier(0.4, 0, 0.2, 1) | Symmetrical state changes (same as default) | Cases where asymmetric timing is preferred |
Keyframe animations
Byteion includes 16 named keyframe animations available via Tailwind animate-* classes. Each is tuned for a specific interaction pattern:
| Class | Purpose | Best component usage |
|---|---|---|
animate-fade-in | Subtle content reveal | Tabs, panels, command palettes |
animate-fade-out | Subtle content hide | Tooltips, dismissible alerts |
animate-slide-up | Content slides up and fades in | Toast, bottom sheet, popover |
animate-slide-down | Content slides down and fades in | Dropdown menu, select options |
animate-slide-in-right | Content slides in from right | Drawer (right), sidebar panel |
animate-slide-in-left | Content slides in from left | Drawer (left), nav sidebar |
animate-slide-in-bottom | Content slides up from below | Mobile bottom sheet, notification panel |
animate-slide-in-top | Content slides down from above | Alert bar, top notification |
animate-scale-in | Grows in from slightly smaller | Modal, dialog, popover opening |
animate-scale-spring | Grows in with a bounce | Checkmarks, selection confirmations |
animate-shake | Horizontal shake for errors | Validation error on inputs, failed actions |
animate-shimmer | Sweeping gradient for loading state | Skeleton loader, placeholder blocks |
animate-pulse-soft | Gentle opacity pulse | Attention state, recording indicator |
animate-check-pop | Icon pops in with spring | Checkbox, radio, success confirmation |
animate-progress-stripes | Animated stripe movement | Progress bar, upload indicator |
animate-progress-indeterminate | Sliding bar for unknown duration | Indeterminate progress, loading bar |
Practical examples
HTML — Button hover transition:
<button class="rounded-button bg-primary px-inset-md py-inset-sm text-sm font-medium text-primary-foreground shadow-button transition-shadow duration-fast hover:shadow-button-hover">
Save
</button>
HTML — Modal with scale-in animation:
<div class="fixed inset-0 z-50 flex items-center justify-center animate-fade-in">
<div class="w-full max-w-lg rounded-overlay border border-border bg-card p-surface-panel shadow-modal animate-scale-in">
<h3 class="text-lg font-semibold text-foreground">Confirm</h3>
<p class="text-sm text-muted-foreground">Are you sure?</p>
</div>
</div>
HTML — Skeleton loading with shimmer:
<div class="space-y-stack-md">
<div class="h-4 w-3/4 rounded-button bg-muted animate-shimmer"></div>
<div class="h-4 w-1/2 rounded-button bg-muted animate-shimmer"></div>
<div class="h-10 w-full rounded-input bg-muted animate-shimmer"></div>
</div>
HTML — Error input with shake:
<div class="space-y-stack-xs">
<label class="text-sm font-medium text-danger">Email</label>
<input class="w-full rounded-input border border-danger bg-background px-inset-md py-inset-sm text-foreground shadow-field-error animate-shake" aria-invalid="true" />
<p class="text-xs text-danger">Please enter a valid email address.</p>
</div>
React:
import { Button, Card, Input } from '@byteion/react';
export default function Form() {
return (
<Card>
<Input label="Name" />
<Button>Submit</Button>
</Card>
);
}
Vue:
<script setup>
import { Button, Card, Input } from '@byteion/vue';
</script>
<template>
<Card>
<Input label="Name" />
<Button>Submit</Button>
</Card>
</template>
Reduced motion
Byteion UI respects the user's operating-system prefers-reduced-motion setting. When enabled, the --motion-* duration variables are set to 0ms, removing almost all transition animation:
@media (prefers-reduced-motion: reduce) {
:root {
--motion-fast: 0ms;
--motion-normal: 0ms;
--motion-slow: 0ms;
}
}
Keyframe animations (such as animate-shimmer and animate-pulse-soft) are not automatically disabled by this rule. If your component uses keyframe animations, consider removing or minimising them when reduced motion is active:
<div class="animate-shimmer motion-reduce:animate-none">...</div>
Components must remain fully functional and visually understandable without motion. Do not rely on animation as the only indicator of state — always pair it with colour, text, or icon changes.
Customization
Motion tokens are defined in packages/tokens/motion.js and consumed through the shared Tailwind preset. The CSS variables in packages/core/theme/variables.css can be overridden at runtime:
:root {
--motion-fast: 80ms;
--motion-normal: 150ms;
--motion-slow: 250ms;
}
- Keep dashboard and admin transitions short. Users in data-heavy interfaces notice delay more than polish.
- Test on slow devices. A 320ms transition on a flagship phone feels like 600ms on a mid-range device — reduce durations if needed.
- Test reduced motion. Verify that every interaction works without animation.
- Avoid changing motion per component unless absolutely necessary — inconsistent timing feels disjointed.
Do and Don't
Do
- Use tokenized durations and easing curves
- Keep motion subtle in dense product screens
- Use motion to clarify state changes, not decorate them
- Test reduced-motion mode before shipping
- Pair motion with visible state, text, colour, or icons
Don't
- Use decorative animation everywhere — every transition should serve a purpose
- Use slow transitions for frequent interactions like toggles or tooltips
- Use spring motion in tables, admin lists, or serious workflows
- Shake inputs repeatedly after every keystroke
- Use motion as the only success or error feedback
Common mistakes
- Over-animating dashboards. Animating every card, row, or stat change creates visual noise in data-heavy screens.
- Using modal-scale-in for small tooltips. A tooltip or badge does not need a full scale-in animation — a quick fade-in is sufficient.
- Making loading shimmer too aggressive. High-contrast shimmer with fast speed distracts users. The default 1.8s cycle is intentionally gentle.
- Forgetting reduced motion. A component that relies on
animate-shakewithout an accessible text alternative fails when motion is reduced. - Mixing random custom cubic-bezier values with Byteion motion tokens. One-off curves bypass the design system and create inconsistent feel.
- Creating one-off animations instead of using existing tokens. Before writing a new keyframe, check whether
animate-fade-in,animate-slide-up, oranimate-scale-incan be composed to achieve the same effect.
Developer tips
ease-out-soft for most transitions. It feels natural and polished — smooth deceleration without overshoot.
• Use ease-spring sparingly. It is designed for celebratory moments (checkmarks, confirmations), not routine interactions.
• Keep animations under 300ms for UI elements. Longer animations feel sluggish in data-heavy enterprise interfaces.
• Pair duration-fast with small state changes. Hover states, focus rings, and toggles should resolve quickly — 120ms is fast enough to feel responsive without being instant.
• Use transition-shadow for hover card elevations. It is cheaper than animating transform or all and avoids layout side effects.
• Always test with reduced motion. Your interface should be fully functional without any animation enabled.Related
- Design Principles — Why tokens matter
- Design Tokens — Source of motion values
- Modal — Scale-in animation on open
- Toast — Slide-up animation
- Dropdown — Open/close motion
- Tooltip — Subtle reveal
- Skeleton — Shimmer loading
- Input — Validation feedback
- Theming Guide — Customising tokens
Unlock Premium Patterns
Get access to copy-paste ready Pro blocks, SaaS templates, and advanced component patterns.
Explore Pro Components