Skip to main content
Version: Next

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

  1. You call a modifier with a target value (and optional configuration)
  2. The modifier returns an animation descriptor
  3. useValue processes the descriptor and animates smoothly
  4. 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 CaseRecommended ModifierWhy
Button hover effectswithSpringNatural, responsive feel
Modal appearancewithSpringSmooth, professional entrance
Tooltip show/hidewithTimingPrecise, predictable timing
Dropdown menuwithTimingQuick, snappy transitions
Drag interactionswithDecayNatural momentum when released
Scroll animationswithDecayRealistic deceleration
Staggered listswithDelaySequential reveals
Multi-step animationswithSequenceChoreographed motion
Loading spinnerswithLoopContinuous animation
Pulsing effectswithLoopRepeating 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 begins
  • onChange - Track progress, update other values
  • onComplete - Chain animations, update state, cleanup

Performance Tips

  1. Use withSpring for most UI animations - It's optimized and feels natural
  2. Use withTiming when you need exact timing - Better for coordinated animations
  3. Avoid too many nested modifiers - Can impact performance
  4. Batch updates - Update multiple properties in one object rather than separate calls

Next Steps

Explore each modifier in detail:

Then learn about: