Skip to main content
Version: Next

View Animations

View animations automatically trigger when elements enter the viewport. The view prop uses Intersection Observer to detect when elements become visible, perfect for scroll-triggered reveals and progressive disclosure.

Basic Usage

The view prop accepts an animation descriptor that runs when the element enters the viewport:

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

function ScrollReveal() {
return (
<animate.div
view={{
opacity: withTiming(1),
translateY: withSpring(0),
}}
style={{
opacity: 0,
translateY: 50,
width: 100,
height: 100,
background: 'teal',
}}
>
Scroll to see me
</animate.div>
);
}

View Options

Control when and how the animation triggers with viewOptions:

<animate.div
view={{
opacity: withTiming(1),
}}
viewOptions={{
threshold: 0.3, // Trigger when 30% visible
once: true, // Only animate once
}}
style={{
opacity: 0,
}}
>
Content
</animate.div>

Available Options

OptionTypeDefaultDescription
thresholdnumber0Percentage of element that must be visible (0-1)
oncebooleanfalseWhether to animate only once
rootMarginstring'0px'Margin around root (e.g., '100px' to trigger earlier)

Real-World Examples

Example 1: Feature Card

function FeatureCard({ title, description }) {
return (
<animate.div
view={{
opacity: withTiming(1, { duration: 600 }),
translateY: withSpring(0),
}}
viewOptions={{
threshold: 0.3,
once: true,
}}
style={{
opacity: 0,
translateY: 50,
padding: 20,
background: 'white',
borderRadius: 8,
boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
}}
>
<h3>{title}</h3>
<p>{description}</p>
</animate.div>
);
}

Example 2: Staggered List

function StaggeredList({ items }) {
return (
<div>
{items.map((item, index) => (
<animate.div
key={item.id}
view={{
opacity: withTiming(1, { duration: 400 }),
translateX: withSpring(0),
}}
viewOptions={{
threshold: 0.2,
once: true,
}}
style={{
opacity: 0,
translateX: -50,
padding: 20,
marginBottom: 10,
background: 'white',
borderRadius: 4,
}}
>
{item.name}
</animate.div>
))}
</div>
);
}

Example 3: Progress Indicator

function ProgressBar() {
return (
<animate.div
view={{
width: withTiming('100%', { duration: 1000 }),
}}
viewOptions={{
threshold: 0.5,
once: true,
}}
style={{
width: '0%',
height: 4,
background: 'teal',
borderRadius: 2,
}}
/>
);
}

Combining with Other Animations

You can combine view with other animation props:

<animate.div
animate={{
opacity: withSpring(1),
}}
view={{
translateY: withSpring(0),
}}
hover={{
scale: withSpring(1.05),
}}
style={{
opacity: 0,
translateY: 50,
}}
>
Multi-animated content
</animate.div>

Performance Tips

  1. Use once: true - Prevents re-animating on scroll
  2. Set appropriate threshold - Don't trigger too early or too late
  3. Use transforms - translateY, translateX are GPU-accelerated
  4. Limit animated properties - Fewer properties = better performance

Best Practices

✅ Do

  • Use once: true for most scroll reveals
  • Set appropriate threshold values (0.2-0.5 is usually good)
  • Use withTiming for predictable scroll animations
  • Test on different screen sizes

❌ Don't

  • Don't animate too many elements at once
  • Don't use view for elements always in viewport
  • Don't forget to set initial styles (opacity: 0, etc.)
  • Don't make animations too slow (users scroll quickly)

Next Steps