Skip to main content
Version: 1.x

Animating with progress

This is where the fun begins. You've wired up your header with HeaderMotion.Header and HeaderMotion.Header.Dynamic — now you can use the progress shared value to animate anything you want.

Getting the values

The useMotionProgress() hook returns two shared values:

const { progress, progressThreshold } = useMotionProgress();
  • progress — a SharedValue<number> going from 0 (header fully expanded) to 1 (header fully collapsed)
  • progressThreshold — a SharedValue<number> containing the collapse distance in pixels

Both are Reanimated shared values, so you use them inside useAnimatedStyle and other Reanimated APIs.

Common animation patterns

Below are building blocks you can mix and match. Each one is a useAnimatedStyle call — combine as many as you need.

Slide the header up

The most fundamental pattern. Move the entire header container upward by the threshold distance so the dynamic section scrolls off screen:

const containerStyle = useAnimatedStyle(() => {
const threshold = progressThreshold.get();
return {
transform: [
{ translateY: interpolate(progress.get(), [0, 1], [0, -threshold]) },
],
};
});

Sticky element (counter-translate)

Make an element appear to stay fixed while the rest of the header moves. Apply an equal-and-opposite translation:

const stickyStyle = useAnimatedStyle(() => {
const threshold = progressThreshold.get();
return {
transform: [
{ translateY: interpolate(progress.get(), [0, 1], [0, threshold]) },
],
};
});

Opacity fade

Fade content out before the header fully collapses — in this example, it disappears by the time progress reaches 0.6:

const fadeStyle = useAnimatedStyle(() => ({
opacity: interpolate(progress.get(), [0, 0.6], [1, 0]),
}));

Scale

Shrink content as the header collapses:

const scaleStyle = useAnimatedStyle(() => ({
transform: [{ scale: interpolate(progress.get(), [0, 1], [1, 0.8]) }],
}));

Parallax

Move content at a fraction of the scroll speed for a depth effect:

const parallaxStyle = useAnimatedStyle(() => {
const threshold = progressThreshold.get();
return {
transform: [
{ translateY: interpolate(progress.get(), [0, 1], [0, threshold * 0.5]) },
],
};
});

Color transition

Use interpolateColor for smooth color shifts:

import { interpolateColor } from 'react-native-reanimated';

const backgroundStyle = useAnimatedStyle(() => ({
backgroundColor: interpolateColor(
progress.get(),
[0, 1],
['#304077', '#1a1a2e']
),
}));

Combining patterns

It's just Reanimated. Because progress is a standard Reanimated SharedValue, you're not limited to the patterns above — anything Reanimated can do, you can drive with progress. These patterns are designed to compose; a typical header might combine a container slide, a sticky element, and a fade + scale on the dynamic section — exactly like the Quick Start example.

What's next?

Learn about the scrollable components that drive the progress value in Default scrollables.