Animation Modifiers Overview
Animation modifiers are functions that tell useValue how to animate. Without a modifier, values change instantly. With modifiers, you get smooth, controlled transitions.
What Are Animation Modifiers?
Think of modifiers as animation "recipes" that describe how a value should change over time:
import { useValue, withSpring, withTiming } from 'react-ui-animate';
const [x, setX] = useValue(0);
// ❌ No modifier - instant change
setX(100);
// ✅ With modifier - smooth animation
setX(withSpring(100));
setX(withTiming(100, { duration: 300 }));
How They Work
- You call a modifier with a target value (and optional configuration)
- The modifier returns an animation descriptor
- useValue processes the descriptor and animates smoothly
- Your component updates automatically as the value changes
const [width, setWidth] = useValue(100);
// withSpring returns an animation descriptor
setWidth(withSpring(200));
// The width smoothly animates from 100 → 200
Available Modifiers
React UI Animate provides several modifiers, each suited for different use cases:
withSpring
Physics-based motion - Natural, bouncy animations that feel organic.
setX(withSpring(100)); // Bouncy, natural motion
Best for: UI elements, cards, modals, buttons, anything that should feel "alive"
withTiming
Time-based transitions - Precise, predictable animations with exact durations.
setX(withTiming(100, { duration: 300 })); // Exact 300ms animation
Best for: Tooltips, dropdowns, precise UI transitions, when you need exact timing
withDecay
Momentum-based motion - Simulates natural deceleration, like friction.
setX(withDecay(0.5)); // Slows down naturally
Best for: Scroll-based animations, drag interactions, momentum scrolling
withDelay
Pause before animation - Waits before starting an animation.
setX(withDelay(500, withSpring(100))); // Wait 500ms, then animate
Best for: Staggered animations, sequential reveals, timed sequences
withSequence
Chain animations - Run multiple animations one after another.
setX(withSequence([
withSpring(50),
withTiming(100),
withSpring(150)
])); // Animates to 50, then 100, then 150
Best for: Complex animations, multi-step transitions, choreographed motion
withLoop
Repeat animations - Loop an animation a specific number of times or infinitely.
setX(withLoop(withSpring(100), 3)); // Repeat 3 times
setX(withLoop(withSpring(100))); // Repeat infinitely
Best for: Loading indicators, pulsing effects, continuous animations
Choosing the Right Modifier
| Use Case | Recommended Modifier | Why |
|---|---|---|
| Button hover effects | withSpring | Natural, responsive feel |
| Modal appearance | withSpring | Smooth, professional entrance |
| Tooltip show/hide | withTiming | Precise, predictable timing |
| Dropdown menu | withTiming | Quick, snappy transitions |
| Drag interactions | withDecay | Natural momentum when released |
| Scroll animations | withDecay | Realistic deceleration |
| Staggered lists | withDelay | Sequential reveals |
| Multi-step animations | withSequence | Choreographed motion |
| Loading spinners | withLoop | Continuous animation |
| Pulsing effects | withLoop | Repeating animations |
Combining Modifiers
You can combine modifiers for complex effects:
// Delay, then spring animation
setX(withDelay(200, withSpring(100)));
// Sequence of different modifiers
setX(withSequence([
withTiming(50, { duration: 200 }),
withSpring(100),
withDecay(0.3)
]));
// Loop a sequence
setX(withLoop(
withSequence([
withSpring(100),
withSpring(0)
]),
3 // Repeat 3 times
));
Common Patterns
Pattern 1: Quick Spring Animation
const [scale, setScale] = useValue(1);
// Quick, snappy spring
const handleClick = () => {
setScale(withSpring(1.2, { stiffness: 300, damping: 20 }));
setTimeout(() => setScale(withSpring(1)), 200);
};
Pattern 2: Precise Timing
const [opacity, setOpacity] = useValue(0);
// Fade in with exact timing
const show = () => {
setOpacity(withTiming(1, { duration: 300 }));
};
// Fade out
const hide = () => {
setOpacity(withTiming(0, { duration: 200 }));
};
Pattern 3: Staggered Animation
const [items, setItems] = useValue([0, 0, 0, 0]);
// Animate each item with a delay
const animateItems = () => {
setItems(withSequence([
withDelay(0, withSpring([100, 0, 0, 0])),
withDelay(100, withSpring([100, 100, 0, 0])),
withDelay(200, withSpring([100, 100, 100, 0])),
withDelay(300, withSpring([100, 100, 100, 100])),
]));
};
Callbacks
All modifiers support lifecycle callbacks:
setX(withSpring(100, {
onStart: () => console.log('Animation started'),
onChange: (value) => console.log('Current value:', value),
onComplete: () => console.log('Animation finished'),
}));
Use cases:
onStart- Trigger side effects when animation beginsonChange- Track progress, update other valuesonComplete- Chain animations, update state, cleanup
Performance Tips
- Use
withSpringfor most UI animations - It's optimized and feels natural - Use
withTimingwhen you need exact timing - Better for coordinated animations - Avoid too many nested modifiers - Can impact performance
- Batch updates - Update multiple properties in one object rather than separate calls
Next Steps
Explore each modifier in detail:
- withSpring - Natural physics-based motion
- withTiming - Precise time-based transitions
- withDecay - Momentum and friction
- withSequence - Chain multiple animations
- withLoop - Repeat animations
- withDelay - Add pauses to animations
Then learn about:
- Presence & Exit - Use these modifiers with Presence for exit animations