withTiming
The withTiming modifier creates precise, time-based animations with exact durations. Unlike withSpring which uses physics, withTiming gives you complete control over how long an animation takes and how it accelerates/decelerates.
Why Use withTiming?
Timing animations are perfect when you need:
- Exact duration - Know exactly how long an animation takes
- Predictable timing - Coordinate multiple animations
- Smooth easing - Control acceleration and deceleration
- Precise control - Perfect for UI transitions, tooltips, dropdowns
Basic Syntax
withTiming(toValue, options?)
Parameters
- toValue (required): The target value. Can be a
number,string,object, orarray. - options (optional): Configuration object for timing control.
Simple Example
The simplest timing animation:
import { useValue, withTiming, animate } from 'react-ui-animate';
function MyComponent() {
const [opacity, setOpacity] = useValue(0);
return (
<>
<button onClick={() => setOpacity(withTiming(1, { duration: 300 }))}>
Fade In
</button>
<animate.div
style={{
opacity,
width: 100,
height: 100,
background: 'teal',
}}
/>
</>
);
}
Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
duration | number | 300 | Animation duration in milliseconds |
easing | function | Linear | Easing function for acceleration/deceleration |
onStart | () => void | - | Called when animation starts |
onChange | (value) => void | - | Called on every frame with current value |
onComplete | () => void | - | Called when animation finishes |
Real-World Examples
Example 1: Fade In/Out
Perfect for tooltips, dropdowns, and modals:
function FadeComponent() {
const [opacity, setOpacity] = useValue(0);
const show = () => {
setOpacity(withTiming(1, { duration: 300 }));
};
const hide = () => {
setOpacity(withTiming(0, { duration: 200 }));
};
return (
<>
<button onClick={show}>Show</button>
<button onClick={hide}>Hide</button>
<animate.div
style={{
opacity,
width: 100,
height: 100,
background: 'teal',
}}
/>
</>
);
}
Example 2: Slide Animation
Smooth slide transitions:
function SlidePanel() {
const [translateX, setTranslateX] = useValue(-200);
const open = () => {
setTranslateX(withTiming(0, { duration: 400 }));
};
const close = () => {
setTranslateX(withTiming(-200, { duration: 300 }));
};
return (
<>
<button onClick={open}>Open</button>
<button onClick={close}>Close</button>
<animate.div
style={{
translateX,
width: 200,
height: '100vh',
background: 'white',
boxShadow: '2px 0 8px rgba(0,0,0,0.1)',
}}
>
Panel Content
</animate.div>
</>
);
}
Example 3: Progress Bar
Animate progress with exact timing:
function ProgressBar() {
const [width, setWidth] = useValue(0);
const start = () => {
setWidth(withTiming(100, { duration: 2000 }));
};
return (
<>
<button onClick={start}>Start Progress</button>
<div style={{ width: 300, height: 8, background: '#e1e1e1', borderRadius: 4 }}>
<animate.div
style={{
width: `${width}%`,
height: '100%',
background: 'teal',
borderRadius: 4,
}}
/>
</div>
</>
);
}
Easing Functions
Control how the animation accelerates and decelerates:
// Linear - constant speed
setX(withTiming(100, { duration: 300 }));
// Ease in - slow start, fast end
setX(withTiming(100, {
duration: 300,
easing: (t) => t * t
}));
// Ease out - fast start, slow end
setX(withTiming(100, {
duration: 300,
easing: (t) => t * (2 - t)
}));
// Ease in-out - slow start and end
setX(withTiming(100, {
duration: 300,
easing: (t) => t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t
}));
Animating Multiple Values
Timing works great with objects and arrays:
const [style, setStyle] = useValue({
opacity: 0,
translateY: 50,
scale: 0.9
});
// Animate all properties together
setStyle(withTiming({
opacity: 1,
translateY: 0,
scale: 1
}, { duration: 400 }));
Using Callbacks
Track animation progress and trigger side effects:
function AnimatedCard() {
const [opacity, setOpacity] = useValue(0);
const fadeIn = () => {
setOpacity(withTiming(1, {
duration: 500,
onStart: () => {
console.log('Fade in started');
// Show loading indicator, disable buttons, etc.
},
onChange: (value) => {
// Track progress
console.log(`Opacity: ${(value * 100).toFixed(0)}%`);
},
onComplete: () => {
console.log('Fade in complete');
// Hide loading indicator, enable buttons, etc.
},
}));
};
return (
<>
<button onClick={fadeIn}>Fade In</button>
<animate.div
style={{
opacity,
width: 100,
height: 100,
background: 'teal',
}}
/>
</>
);
}
Common Patterns
Pattern 1: Quick Fade
const [opacity, setOpacity] = useValue(0);
const show = () => {
setOpacity(withTiming(1, { duration: 200 }));
};
const hide = () => {
setOpacity(withTiming(0, { duration: 150 }));
};
Pattern 2: Coordinated Animations
const [opacity, setOpacity] = useValue(0);
const [translateY, setTranslateY] = useValue(50);
// Animate both with same duration for coordination
const reveal = () => {
setOpacity(withTiming(1, { duration: 400 }));
setTranslateY(withTiming(0, { duration: 400 }));
};
Pattern 3: Staggered Timing
const [items, setItems] = useValue([0, 0, 0, 0]);
const reveal = () => {
// Each item fades in 100ms after the previous
items.forEach((_, i) => {
setTimeout(() => {
const newItems = [...items];
newItems[i] = 1;
setItems(newItems);
}, i * 100);
});
};
When to Use withTiming vs withSpring
| Use Case | Recommended Modifier | Why |
|---|---|---|
| Tooltips | withTiming | Quick, predictable timing |
| Dropdowns | withTiming | Snappy, controlled |
| Progress bars | withTiming | Exact duration needed |
| Modals | withSpring | Natural, bouncy feel |
| Buttons | withSpring | Responsive, alive |
| Cards | withSpring | Organic motion |
Best Practices
✅ Do
- Use
withTimingwhen you need exact duration - Use consistent durations across related animations
- Use easing functions for natural acceleration/deceleration
- Leverage callbacks for coordination and side effects
❌ Don't
- Don't use
withTimingwhen you want natural, bouncy motion (usewithSpring) - Don't make animations too slow (>1000ms) - users expect quick feedback
- Don't forget to handle the animation lifecycle with callbacks
- Don't animate layout properties - use transforms instead
Performance Tips
- Timing is optimized - Very performant for simple animations
- Use transforms -
translateX,translateY,scaleare GPU-accelerated - Batch updates - Animate multiple properties in one object
- Keep durations reasonable - 200-500ms is usually ideal
Troubleshooting
Animation feels too fast:
- Increase
duration(try 400-600ms)
Animation feels too slow:
- Decrease
duration(try 150-250ms)
Animation feels mechanical:
- Add easing function for natural acceleration/deceleration
- Or consider using
withSpringfor more natural motion
Next Steps
- Learn about withSpring for natural physics-based motion
- Explore withSequence to chain timing animations
- Check out Presence & Exit for exit animations