Skip to main content
Version: Next

withDelay

The withDelay modifier adds a pause before an animation starts. Perfect for creating staggered animations, sequential reveals, and timed sequences where you need precise control over when animations begin.

Why Use withDelay?

Delay is essential for:

  • Staggered animations - Reveal items one after another
  • Sequential reveals - Guide users through content
  • Timed sequences - Coordinate multiple animations
  • Pacing control - Add breathing room between animations

Basic Syntax

withDelay(ms, animation)

Parameters

  • ms (required): Delay time in milliseconds
  • animation (required): The animation descriptor to run after the delay

Simple Example

Add a delay before an animation:

import { useValue, withDelay, withSpring, animate } from 'react-ui-animate';

function MyComponent() {
const [x, setX] = useValue(0);

const animateWithDelay = () => {
setX(withDelay(500, withSpring(200)));
};

return (
<>
<button onClick={animateWithDelay}>Animate (with 500ms delay)</button>
<animate.div
style={{
translateX: x,
width: 100,
height: 100,
background: 'teal',
}}
/>
</>
);
}

Real-World Examples

Example 1: Staggered List Items

Reveal items one by one:

function StaggeredList({ items }) {
const [heights, setHeights] = useValue(items.map(() => 0));

const reveal = () => {
setHeights(withSequence(
items.map((_, i) =>
withDelay(i * 100, withSpring(100))
)
));
};

return (
<>
<button onClick={reveal}>Reveal Items</button>
{items.map((item, i) => (
<animate.div
key={item.id}
style={{
height: heights[i],
background: 'teal',
marginBottom: 10,
padding: 10,
}}
>
{item.name}
</animate.div>
))}
</>
);
}

Example 2: Sequential Card Reveal

Cards appear one after another:

function CardGrid({ cards }) {
const [opacities, setOpacities] = useValue(cards.map(() => 0));

useEffect(() => {
setOpacities(withSequence(
cards.map((_, i) =>
withDelay(i * 150, withTiming(1, { duration: 400 }))
)
));
}, []);

return (
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 20 }}>
{cards.map((card, i) => (
<animate.div
key={card.id}
style={{
opacity: opacities[i],
translateY: (1 - opacities[i]) * 20,
background: 'white',
padding: 20,
borderRadius: 8,
}}
>
{card.title}
</animate.div>
))}
</div>
);
}

Example 3: Notification with Delay

Show notification, wait, then hide:

function DelayedNotification({ message, isVisible }) {
const [opacity, setOpacity] = useValue(0);

useEffect(() => {
if (isVisible) {
setOpacity(withSequence([
// Show immediately
withTiming(1, { duration: 300 }),
// Wait 3 seconds
withDelay(3000),
// Hide
withTiming(0, { duration: 300 }),
]));
}
}, [isVisible]);

return (
<animate.div
style={{
opacity,
position: 'fixed',
bottom: 20,
right: 20,
background: '#333',
color: 'white',
padding: '12px 24px',
borderRadius: 8,
}}
>
{message}
</animate.div>
);
}

Example 4: Multi-Step Animation

Chain animations with delays:

function MultiStepAnimation() {
const [style, setStyle] = useValue({
x: 0,
y: 0,
scale: 1,
});

const animate = () => {
setStyle(withSequence([
// Step 1: Move right (immediate)
withSpring({ x: 100 }),
// Step 2: Wait, then move down
withDelay(500, withSpring({ y: 100 })),
// Step 3: Wait, then scale up
withDelay(500, withSpring({ scale: 1.5 })),
// Step 4: Wait, then return
withDelay(1000, withSpring({ x: 0, y: 0, scale: 1 })),
]));
};

return (
<>
<button onClick={animate}>Animate</button>
<animate.div
style={{
translateX: style.x,
translateY: style.y,
scale: style.scale,
width: 100,
height: 100,
background: 'teal',
}}
/>
</>
);
}

Using in Sequences

withDelay is commonly used within withSequence:

setX(withSequence([
withSpring(100),
withDelay(500), // Pause for 500ms
withTiming(200, { duration: 300 }),
withDelay(1000), // Pause for 1 second
withSpring(0),
]));

Common Patterns

Pattern 1: Staggered Reveal

const [opacities, setOpacities] = useValue([0, 0, 0, 0]);

const reveal = () => {
setOpacities(withSequence([
withDelay(0, withTiming([1, 0, 0, 0])),
withDelay(100, withTiming([1, 1, 0, 0])),
withDelay(200, withTiming([1, 1, 1, 0])),
withDelay(300, withTiming([1, 1, 1, 1])),
]));
};

Pattern 2: Sequential Actions

const [step, setStep] = useValue(0);

const executeSteps = () => {
setStep(withSequence([
withTiming(1), // Step 1
withDelay(500),
withTiming(2), // Step 2
withDelay(500),
withTiming(3), // Step 3
]));
};

Pattern 3: Typing Effect

const [text, setText] = useValue('');

const typeText = (fullText) => {
const sequence = fullText.split('').map((_, i) =>
withDelay(i * 50, () => {
setText(fullText.slice(0, i + 1));
})
);
// Execute sequence
};

Best Practices

✅ Do

  • Use delays for staggered animations (100-200ms between items)
  • Use delays in sequences for pacing
  • Keep delays reasonable (50-500ms for most cases)
  • Use delays to create breathing room between animations

❌ Don't

  • Don't use delays that are too long (>2000ms) - users expect quick feedback
  • Don't delay user-triggered animations unnecessarily
  • Don't forget that delays add to total animation time
  • Don't use delays when immediate feedback is needed

Performance Tips

  1. Delays are lightweight - Very performant
  2. Batch delays - Use sequences to coordinate multiple delayed animations
  3. Consider total time - Long delays can make interfaces feel slow
  4. Use for reveals - Perfect for scroll-triggered or initial load animations

Troubleshooting

Animation doesn't start after delay:

  • Check that the delay value is correct
  • Verify the animation descriptor is valid
  • Ensure the component is still mounted

Delay feels too long:

  • Reduce delay time (try 50-200ms for staggered)
  • Consider if delay is necessary

Multiple delays feel janky:

  • Use withSequence to coordinate delays
  • Ensure delays are consistent (same interval)

Next Steps