React Native for Web is a comprehensive compatibility library that enables React Native components and APIs to run seamlessly on web browsers using React DOM.
—
React Native's Animated API adapted for web with full support for declarative animations, timing functions, spring physics, and composition utilities for building complex animated UIs.
The main Animated API providing declarative animation capabilities with configurable transforms, value management, and timing control for building fluid, maintainable animations.
const Animated: {
// Value Classes
Value: typeof AnimatedValue;
ValueXY: typeof AnimatedValueXY;
Color: typeof AnimatedColor;
// Animation Functions
timing: (value: AnimatedValue | AnimatedValueXY | AnimatedColor, config: TimingAnimationConfig) => CompositeAnimation;
spring: (value: AnimatedValue | AnimatedValueXY | AnimatedColor, config: SpringAnimationConfig) => CompositeAnimation;
decay: (value: AnimatedValue | AnimatedValueXY | AnimatedColor, config: DecayAnimationConfig) => CompositeAnimation;
// Composition Functions
parallel: (animations: CompositeAnimation[], config?: ParallelConfig) => CompositeAnimation;
sequence: (animations: CompositeAnimation[]) => CompositeAnimation;
stagger: (time: number, animations: CompositeAnimation[]) => CompositeAnimation;
delay: (time: number) => CompositeAnimation;
loop: (animation: CompositeAnimation, config?: LoopAnimationConfig) => CompositeAnimation;
// Math Operations
add: (a: AnimatedNode | number, b: AnimatedNode | number) => AnimatedAddition;
subtract: (a: AnimatedNode | number, b: AnimatedNode | number) => AnimatedSubtraction;
multiply: (a: AnimatedNode | number, b: AnimatedNode | number) => AnimatedMultiplication;
divide: (a: AnimatedNode | number, b: AnimatedNode | number) => AnimatedDivision;
modulo: (a: AnimatedNode, modulus: number) => AnimatedModulo;
diffClamp: (a: AnimatedNode, min: number, max: number) => AnimatedDiffClamp;
// Event Handling
event: (argMapping: Mapping[], config: EventConfig) => Function;
forkEvent: (event: AnimatedEvent | Function, listener: Function) => AnimatedEvent | Function;
unforkEvent: (event: AnimatedEvent | Function, listener: Function) => void;
// Components
View: typeof AnimatedView;
Text: typeof AnimatedText;
Image: typeof AnimatedImage;
ScrollView: typeof AnimatedScrollView;
FlatList: typeof AnimatedFlatList;
SectionList: typeof AnimatedSectionList;
// Utilities
createAnimatedComponent: <T>(Component: T) => T;
attachNativeEvent: (viewRef: any, eventName: string, argMapping: Mapping[]) => void;
// Type Exports
Node: typeof AnimatedNode;
Interpolation: typeof AnimatedInterpolation;
Event: typeof AnimatedEvent;
};Comprehensive easing functions library providing mathematically accurate timing curves for animations. Includes predefined animations, standard mathematical functions, and helper functions for creating custom easing behaviors.
const Easing: {
// Predefined animations
ease: (t: number) => number;
bounce: (t: number) => number;
back: (s?: number) => (t: number) => number;
elastic: (bounciness?: number) => (t: number) => number;
// Standard functions
linear: (t: number) => number;
quad: (t: number) => number;
cubic: (t: number) => number;
poly: (n: number) => (t: number) => number;
// Mathematical functions
sin: (t: number) => number;
circle: (t: number) => number;
exp: (t: number) => number;
bezier: (x1: number, y1: number, x2: number, y2: number) => (t: number) => number;
// Stepping functions
step0: (n: number) => number;
step1: (n: number) => number;
// Direction helpers
in: (easing: (t: number) => number) => (t: number) => number;
out: (easing: (t: number) => number) => (t: number) => number;
inOut: (easing: (t: number) => number) => (t: number) => number;
};Web Implementation: All easing functions are implemented using pure JavaScript mathematical functions, providing consistent behavior across all platforms and browsers.
// Simple inertial animation, similar to CSS ease
Easing.ease(t: number): number
// Bouncing animation with multiple bounces
Easing.bounce(t: number): number
// Animation that goes slightly back before moving forward
Easing.back(s?: number): (t: number) => number
// Spring-like elastic animation with configurable bounciness
Easing.elastic(bounciness?: number): (t: number) => number// Linear timing (no easing)
Easing.linear(t: number): number
// Quadratic timing (t²)
Easing.quad(t: number): number
// Cubic timing (t³)
Easing.cubic(t: number): number
// Power timing (t^n)
Easing.poly(n: number): (t: number) => number// Sinusoidal timing
Easing.sin(t: number): number
// Circular timing
Easing.circle(t: number): number
// Exponential timing
Easing.exp(t: number): number
// Cubic Bézier curve (like CSS transition-timing-function)
Easing.bezier(x1: number, y1: number, x2: number, y2: number): (t: number) => number// Run easing function forwards (identity function)
Easing.in(easing: (t: number) => number): (t: number) => number
// Run easing function backwards
Easing.out(easing: (t: number) => number): (t: number) => number
// Make easing function symmetrical (ease in for first half, ease out for second half)
Easing.inOut(easing: (t: number) => number): (t: number) => numberUsage:
import { Animated, Easing } from "react-native-web";
function EasingExample() {
const fadeAnim = new Animated.Value(0);
const slideAnim = new Animated.Value(-100);
const startAnimation = () => {
Animated.parallel([
// Fade in with custom cubic bezier
Animated.timing(fadeAnim, {
toValue: 1,
duration: 500,
easing: Easing.bezier(0.25, 0.1, 0.25, 1), // CSS ease
useNativeDriver: false,
}),
// Slide in with elastic bounce
Animated.timing(slideAnim, {
toValue: 0,
duration: 800,
easing: Easing.elastic(1.5),
useNativeDriver: false,
}),
// Complex custom easing using helpers
Animated.timing(rotateAnim, {
toValue: 360,
duration: 1000,
easing: Easing.inOut(Easing.back(2)),
useNativeDriver: false,
}),
]).start();
};
return (
<Animated.View
style={{
opacity: fadeAnim,
transform: [
{ translateX: slideAnim },
{ rotate: rotateAnim.interpolate({
inputRange: [0, 360],
outputRange: ['0deg', '360deg']
})}
],
}}
>
<Text>Animated with custom easing!</Text>
</Animated.View>
);
}
// Compare different easing functions
const easingComparison = {
linear: Easing.linear,
ease: Easing.ease,
easeOut: Easing.out(Easing.quad),
easeInOut: Easing.inOut(Easing.cubic),
bounce: Easing.bounce,
elastic: Easing.elastic(1),
back: Easing.back(),
};Standard animated value class for driving single-property animations.
class AnimatedValue extends AnimatedNode {
constructor(value: number, config?: AnimatedValueConfig): AnimatedValue;
setValue(value: number): void;
setOffset(offset: number): void;
flattenOffset(): void;
extractOffset(): void;
addListener(callback: ValueListenerCallback): string;
removeListener(id: string): void;
removeAllListeners(): void;
stopAnimation(callback?: (value: number) => void): void;
resetAnimation(callback?: (value: number) => void): void;
interpolate(config: InterpolationConfigType): AnimatedInterpolation;
animate(animation: Animation, callback?: EndCallback): void;
stopTracking(): void;
track(tracking: AnimatedTracking): void;
}Usage:
import { Animated, View } from "react-native-web";
function FadeInView({ children }) {
const fadeAnim = new Animated.Value(0);
React.useEffect(() => {
Animated.timing(fadeAnim, {
toValue: 1,
duration: 1000,
useNativeDriver: false
}).start();
}, [fadeAnim]);
return (
<Animated.View style={{ opacity: fadeAnim }}>
{children}
</Animated.View>
);
}
// Advanced value manipulation
function ComplexAnimation() {
const translateX = new Animated.Value(0);
const scale = new Animated.Value(1);
// Set initial value
translateX.setValue(50);
// Add offset (current value becomes offset + value)
translateX.setOffset(100);
translateX.setValue(0); // Now animates from 100
// Listen to value changes
const listenerId = translateX.addListener(({ value }) => {
console.log(`TranslateX: ${value}`);
});
// Interpolate for different properties
const backgroundColor = translateX.interpolate({
inputRange: [0, 100],
outputRange: ['rgba(255,0,0,0.5)', 'rgba(0,0,255,0.5)'],
extrapolate: 'clamp'
});
return (
<Animated.View
style={{
transform: [
{ translateX },
{ scale }
],
backgroundColor
}}
/>
);
}2D animated value class for driving pan gestures and multi-dimensional animations.
class AnimatedValueXY extends AnimatedNode {
x: AnimatedValue;
y: AnimatedValue;
constructor(valueIn?: { x: number | AnimatedValue; y: number | AnimatedValue }, config?: AnimatedValueConfig): AnimatedValueXY;
setValue(value: { x: number; y: number }): void;
setOffset(offset: { x: number; y: number }): void;
flattenOffset(): void;
extractOffset(): void;
stopAnimation(callback?: (value: { x: number; y: number }) => void): void;
resetAnimation(callback?: (value: { x: number; y: number }) => void): void;
addListener(callback: ValueXYListenerCallback): string;
removeListener(id: string): void;
removeAllListeners(): void;
getLayout(): { left: AnimatedValue; top: AnimatedValue };
getTranslateTransform(): [{ translateX: AnimatedValue }, { translateY: AnimatedValue }];
}Usage:
// Pan gesture with ValueXY
function DraggableBox() {
const pan = new Animated.ValueXY();
const panGesture = PanGestureHandler.create({
onGestureEvent: Animated.event(
[{ nativeEvent: { translationX: pan.x, translationY: pan.y } }],
{ useNativeDriver: false }
),
onHandlerStateChange: (event) => {
if (event.nativeEvent.oldState === State.ACTIVE) {
// Snap back to center
Animated.spring(pan, {
toValue: { x: 0, y: 0 },
useNativeDriver: false
}).start();
}
}
});
return (
<PanGestureHandler {...panGesture}>
<Animated.View
style={{
transform: pan.getTranslateTransform(),
width: 100,
height: 100,
backgroundColor: 'blue'
}}
/>
</PanGestureHandler>
);
}
// Complex 2D animation
function Orbit() {
const position = new Animated.ValueXY({ x: 0, y: 0 });
const angle = new Animated.Value(0);
React.useEffect(() => {
const animateOrbit = () => {
const radius = 50;
angle.setValue(0);
Animated.timing(angle, {
toValue: 2 * Math.PI,
duration: 2000,
useNativeDriver: false
}).start(() => animateOrbit());
};
animateOrbit();
}, []);
// Convert polar to cartesian coordinates
const x = Animated.multiply(
Animated.add(Math.cos, angle),
radius
);
const y = Animated.multiply(
Animated.add(Math.sin, angle),
radius
);
return (
<Animated.View
style={{
position: 'absolute',
left: x,
top: y,
width: 20,
height: 20,
backgroundColor: 'red',
borderRadius: 10
}}
/>
);
}Animated value class for color animations with RGBA channel support.
class AnimatedColor extends AnimatedNode {
r: AnimatedValue;
g: AnimatedValue;
b: AnimatedValue;
a: AnimatedValue;
constructor(valueIn?: string | { r: number; g: number; b: number; a: number }): AnimatedColor;
setValue(value: string): void;
}Animates a value along a timed easing curve with configurable duration and easing function.
Animated.timing(
value: AnimatedValue | AnimatedValueXY | AnimatedColor,
config: {
toValue: number | AnimatedValue | { x: number; y: number } | string;
duration?: number; // default: 500
easing?: EasingFunction; // default: Easing.inOut(Easing.ease)
delay?: number; // default: 0
useNativeDriver?: boolean; // default: false
onComplete?: (result: EndResult) => void;
}
): CompositeAnimationUsage:
// Basic timing animation
const opacity = new Animated.Value(0);
Animated.timing(opacity, {
toValue: 1,
duration: 300,
useNativeDriver: false
}).start();
// Custom easing functions
import { Easing } from "react-native-web";
Animated.timing(opacity, {
toValue: 1,
duration: 500,
easing: Easing.bezier(0.25, 0.1, 0.25, 1), // Custom bezier
useNativeDriver: false
}).start();
// Sequential timing with callbacks
function SequentialAnimation() {
const slideIn = new Animated.Value(-100);
const fadeIn = new Animated.Value(0);
const animateIn = () => {
Animated.timing(slideIn, {
toValue: 0,
duration: 300,
easing: Easing.out(Easing.back(1.7)),
useNativeDriver: false
}).start(({ finished }) => {
if (finished) {
Animated.timing(fadeIn, {
toValue: 1,
duration: 200,
useNativeDriver: false
}).start();
}
});
};
return (
<Animated.View
style={{
transform: [{ translateX: slideIn }],
opacity: fadeIn
}}
/>
);
}Animates a value according to an analytical spring model based on damped harmonic oscillation.
Animated.spring(
value: AnimatedValue | AnimatedValueXY | AnimatedColor,
config: {
toValue: number | AnimatedValue | { x: number; y: number };
restDisplacementThreshold?: number; // default: 0.001
restSpeedThreshold?: number; // default: 0.001
velocity?: number | { x: number; y: number }; // default: 0
bounciness?: number; // default: 8
speed?: number; // default: 12
tension?: number; // alternative to bounciness/speed
friction?: number; // alternative to bounciness/speed
stiffness?: number; // alternative spring config
damping?: number; // alternative spring config
mass?: number; // default: 1
useNativeDriver?: boolean; // default: false
onComplete?: (result: EndResult) => void;
}
): CompositeAnimationUsage:
// Bouncy spring animation
const scale = new Animated.Value(0);
Animated.spring(scale, {
toValue: 1,
bounciness: 15,
speed: 8,
useNativeDriver: false
}).start();
// Physics-based spring
Animated.spring(scale, {
toValue: 1,
tension: 100,
friction: 8,
velocity: 0.5,
useNativeDriver: false
}).start();
// Interactive spring with gesture
function SpringButton({ onPress, children }) {
const scale = new Animated.Value(1);
const opacity = new Animated.Value(1);
const animateIn = () => {
Animated.parallel([
Animated.spring(scale, {
toValue: 0.95,
tension: 300,
friction: 10,
useNativeDriver: false
}),
Animated.timing(opacity, {
toValue: 0.8,
duration: 100,
useNativeDriver: false
})
]).start();
};
const animateOut = () => {
Animated.parallel([
Animated.spring(scale, {
toValue: 1,
tension: 300,
friction: 10,
useNativeDriver: false
}),
Animated.timing(opacity, {
toValue: 1,
duration: 100,
useNativeDriver: false
})
]).start();
};
return (
<TouchableWithoutFeedback
onPressIn={animateIn}
onPressOut={animateOut}
onPress={onPress}
>
<Animated.View
style={{
transform: [{ scale }],
opacity
}}
>
{children}
</Animated.View>
</TouchableWithoutFeedback>
);
}Animates a value from an initial velocity to zero based on a decay coefficient.
Animated.decay(
value: AnimatedValue | AnimatedValueXY | AnimatedColor,
config: {
velocity: number | { x: number; y: number };
deceleration?: number; // default: 0.998
useNativeDriver?: boolean; // default: false
onComplete?: (result: EndResult) => void;
}
): CompositeAnimationUsage:
// Scroll momentum simulation
function MomentumScroll() {
const scrollY = new Animated.Value(0);
let lastScrollY = 0;
let velocity = 0;
const handleScroll = (event) => {
const currentScrollY = event.nativeEvent.contentOffset.y;
velocity = currentScrollY - lastScrollY;
lastScrollY = currentScrollY;
scrollY.setValue(currentScrollY);
};
const handleScrollEnd = () => {
if (Math.abs(velocity) > 0.1) {
Animated.decay(scrollY, {
velocity: velocity,
deceleration: 0.995,
useNativeDriver: false
}).start();
}
};
return (
<ScrollView
onScroll={handleScroll}
onScrollEndDrag={handleScrollEnd}
scrollEventThrottle={16}
>
{/* Content */}
</ScrollView>
);
}Starts multiple animations simultaneously with optional coordination.
Animated.parallel(
animations: CompositeAnimation[],
config?: {
stopTogether?: boolean; // default: true
}
): CompositeAnimationRuns animations in sequential order, waiting for each to complete.
Animated.sequence(animations: CompositeAnimation[]): CompositeAnimationStarts animations in sequence with successive delays.
Animated.stagger(
time: number,
animations: CompositeAnimation[]
): CompositeAnimationContinuously repeats an animation with configurable iterations.
Animated.loop(
animation: CompositeAnimation,
config?: {
iterations?: number; // default: -1 (infinite)
resetBeforeIteration?: boolean; // default: true
}
): CompositeAnimationUsage:
// Complex choreographed animation
function StaggeredCards() {
const cards = [0, 1, 2, 3].map(() => ({
opacity: new Animated.Value(0),
translateY: new Animated.Value(50),
scale: new Animated.Value(0.8)
}));
const animateIn = () => {
const cardAnimations = cards.map(({ opacity, translateY, scale }) =>
Animated.parallel([
Animated.timing(opacity, {
toValue: 1,
duration: 300,
useNativeDriver: false
}),
Animated.spring(translateY, {
toValue: 0,
tension: 100,
friction: 8,
useNativeDriver: false
}),
Animated.spring(scale, {
toValue: 1,
tension: 120,
friction: 7,
useNativeDriver: false
})
])
);
// Stagger the card animations
Animated.stagger(100, cardAnimations).start();
};
const pulseAnimation = () => {
const pulseScale = new Animated.Value(1);
return Animated.loop(
Animated.sequence([
Animated.timing(pulseScale, {
toValue: 1.05,
duration: 800,
useNativeDriver: false
}),
Animated.timing(pulseScale, {
toValue: 1,
duration: 800,
useNativeDriver: false
})
]),
{ iterations: -1 }
);
};
return (
<View>
{cards.map(({ opacity, translateY, scale }, index) => (
<Animated.View
key={index}
style={{
opacity,
transform: [{ translateY }, { scale }]
}}
>
<Text>Card {index + 1}</Text>
</Animated.View>
))}
</View>
);
}Combine animated values using mathematical operations for complex derived animations.
Animated.add(a: AnimatedNode | number, b: AnimatedNode | number): AnimatedAddition;
Animated.subtract(a: AnimatedNode | number, b: AnimatedNode | number): AnimatedSubtraction;
Animated.multiply(a: AnimatedNode | number, b: AnimatedNode | number): AnimatedMultiplication;
Animated.divide(a: AnimatedNode | number, b: AnimatedNode | number): AnimatedDivision;
Animated.modulo(a: AnimatedNode, modulus: number): AnimatedModulo;
Animated.diffClamp(a: AnimatedNode, min: number, max: number): AnimatedDiffClamp;Usage:
// Complex derived animations
function ParallaxHeader() {
const scrollY = new Animated.Value(0);
const headerHeight = 200;
// Clamp scroll for header transformation
const headerTranslateY = Animated.diffClamp(
scrollY,
0,
headerHeight
).interpolate({
inputRange: [0, headerHeight],
outputRange: [0, -headerHeight],
extrapolate: 'clamp'
});
// Combine multiple values
const headerScale = Animated.add(
1,
Animated.divide(scrollY, headerHeight * 2)
);
const headerOpacity = Animated.subtract(
1,
Animated.divide(scrollY, headerHeight)
);
return (
<View>
<Animated.View
style={{
height: headerHeight,
transform: [
{ translateY: headerTranslateY },
{ scale: headerScale }
],
opacity: headerOpacity
}}
>
<Text>Parallax Header</Text>
</Animated.View>
<ScrollView
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { y: scrollY } } }],
{ useNativeDriver: false }
)}
scrollEventThrottle={16}
>
{/* Content */}
</ScrollView>
</View>
);
}
// Mathematical operations for physics
function PhysicsAnimation() {
const x = new Animated.Value(0);
const velocity = new Animated.Value(0);
// Kinetic energy calculation: KE = 0.5 * m * v²
const kineticEnergy = Animated.multiply(
0.5,
Animated.multiply(velocity, velocity)
);
// Oscillation with sine wave
const time = new Animated.Value(0);
const amplitude = 50;
const sinePosition = Animated.multiply(
amplitude,
// Note: In real implementation, you'd need to use interpolation
// for trigonometric functions
time.interpolate({
inputRange: [0, Math.PI * 2],
outputRange: [0, 1, 0, -1, 0],
extrapolate: 'extend'
})
);
return (
<Animated.View
style={{
transform: [{ translateX: sinePosition }]
}}
/>
);
}Maps gesture or scroll events directly to animated values for high-performance interactions.
Animated.event(
argMapping: Mapping[],
config?: {
useNativeDriver?: boolean; // default: false
listener?: Function;
}
): FunctionUsage:
// Scroll-driven animations
function ScrollParallax() {
const scrollY = new Animated.Value(0);
return (
<ScrollView
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { y: scrollY } } }],
{
useNativeDriver: false,
listener: (event) => {
// Additional scroll handling
console.log('Scroll position:', event.nativeEvent.contentOffset.y);
}
}
)}
scrollEventThrottle={16}
>
<Animated.View
style={{
transform: [{
translateY: scrollY.interpolate({
inputRange: [0, 100],
outputRange: [0, -50],
extrapolate: 'clamp'
})
}]
}}
>
{/* Parallax content */}
</Animated.View>
</ScrollView>
);
}
// Pan gesture handling
function PanAnimation() {
const pan = new Animated.ValueXY();
return (
<View>
<Animated.View
{...PanResponder.create({
onMoveShouldSetPanResponder: () => true,
onPanResponderGrant: () => {
pan.setOffset({
x: pan.x._value,
y: pan.y._value
});
},
onPanResponderMove: Animated.event(
[null, { dx: pan.x, dy: pan.y }],
{ useNativeDriver: false }
),
onPanResponderRelease: () => {
pan.flattenOffset();
Animated.spring(pan, {
toValue: { x: 0, y: 0 },
useNativeDriver: false
}).start();
}
}).panHandlers}
style={{
transform: pan.getTranslateTransform()
}}
>
{/* Draggable content */}
</Animated.View>
</View>
);
}Pre-built animated versions of common React Native components.
const AnimatedComponents: {
View: AnimatedComponent<typeof View>;
Text: AnimatedComponent<typeof Text>;
Image: AnimatedComponent<typeof Image>;
ScrollView: AnimatedComponent<typeof ScrollView>;
FlatList: AnimatedComponent<typeof FlatList>;
SectionList: AnimatedComponent<typeof SectionList>;
};Creates animated versions of custom components.
Animated.createAnimatedComponent<T>(Component: T): TUsage:
// Create custom animated component
const AnimatedTouchableOpacity = Animated.createAnimatedComponent(TouchableOpacity);
function CustomAnimatedButton({ onPress, children }) {
const scale = new Animated.Value(1);
const opacity = new Animated.Value(1);
const handlePressIn = () => {
Animated.parallel([
Animated.spring(scale, {
toValue: 0.95,
useNativeDriver: false
}),
Animated.timing(opacity, {
toValue: 0.7,
duration: 100,
useNativeDriver: false
})
]).start();
};
const handlePressOut = () => {
Animated.parallel([
Animated.spring(scale, {
toValue: 1,
useNativeDriver: false
}),
Animated.timing(opacity, {
toValue: 1,
duration: 100,
useNativeDriver: false
})
]).start();
};
return (
<AnimatedTouchableOpacity
onPress={onPress}
onPressIn={handlePressIn}
onPressOut={handlePressOut}
style={{
transform: [{ scale }],
opacity
}}
>
{children}
</AnimatedTouchableOpacity>
);
}
// Advanced custom component with multiple animated properties
const AnimatedGradientView = Animated.createAnimatedComponent(
({ colors, style, children, ...props }) => (
<View
{...props}
style={[
{
background: `linear-gradient(45deg, ${colors.join(', ')})`
},
style
]}
>
{children}
</View>
)
);Transform animated values into different ranges and types for versatile property mapping.
animatedValue.interpolate({
inputRange: number[];
outputRange: (number | string)[];
easing?: EasingFunction;
extrapolate?: 'extend' | 'identity' | 'clamp';
extrapolateLeft?: 'extend' | 'identity' | 'clamp';
extrapolateRight?: 'extend' | 'identity' | 'clamp';
}): AnimatedInterpolationUsage:
// Color interpolation
function ColorTransition() {
const animatedValue = new Animated.Value(0);
const backgroundColor = animatedValue.interpolate({
inputRange: [0, 0.5, 1],
outputRange: ['#ff0000', '#ffff00', '#00ff00']
});
const textColor = animatedValue.interpolate({
inputRange: [0, 1],
outputRange: ['rgba(255,255,255,1)', 'rgba(0,0,0,1)']
});
return (
<Animated.View style={{ backgroundColor }}>
<Animated.Text style={{ color: textColor }}>
Color Transition
</Animated.Text>
</Animated.View>
);
}
// Multi-property interpolation
function ComplexInterpolation() {
const scrollY = new Animated.Value(0);
// Multiple interpolated properties from single value
const headerOpacity = scrollY.interpolate({
inputRange: [0, 50, 100],
outputRange: [1, 0.5, 0],
extrapolate: 'clamp'
});
const headerScale = scrollY.interpolate({
inputRange: [0, 100],
outputRange: [1, 0.8],
extrapolate: 'clamp'
});
const titleFontSize = scrollY.interpolate({
inputRange: [0, 100],
outputRange: [24, 18],
extrapolate: 'clamp'
});
const borderRadius = scrollY.interpolate({
inputRange: [0, 50],
outputRange: [0, 15],
extrapolate: 'clamp'
});
return (
<Animated.View
style={{
opacity: headerOpacity,
transform: [{ scale: headerScale }],
borderRadius
}}
>
<Animated.Text
style={{
fontSize: titleFontSize
}}
>
Dynamic Header
</Animated.Text>
</Animated.View>
);
}React Native Web's Animated implementation provides full compatibility with React Native's API while leveraging web-native CSS transitions and transforms for optimal performance.
Key Features:
Animated.event()Performance Notes:
useNativeDriver: true for transform and opacity animations when availableinterface CompositeAnimation {
start(callback?: EndCallback): void;
stop(): void;
reset(): void;
_startNativeLoop(iterations?: number): void;
_isUsingNativeDriver(): boolean;
}
interface AnimatedValueConfig {
useNativeDriver?: boolean;
}
interface TimingAnimationConfig {
toValue: number | AnimatedValue;
duration?: number;
easing?: EasingFunction;
delay?: number;
useNativeDriver?: boolean;
onComplete?: (result: EndResult) => void;
}
interface SpringAnimationConfig {
toValue: number | AnimatedValue;
restDisplacementThreshold?: number;
restSpeedThreshold?: number;
velocity?: number;
bounciness?: number;
speed?: number;
tension?: number;
friction?: number;
stiffness?: number;
damping?: number;
mass?: number;
useNativeDriver?: boolean;
onComplete?: (result: EndResult) => void;
}
interface DecayAnimationConfig {
velocity: number;
deceleration?: number;
useNativeDriver?: boolean;
onComplete?: (result: EndResult) => void;
}
interface ParallelConfig {
stopTogether?: boolean;
}
interface LoopAnimationConfig {
iterations?: number;
resetBeforeIteration?: boolean;
}
interface InterpolationConfigType {
inputRange: number[];
outputRange: (number | string)[];
easing?: EasingFunction;
extrapolate?: 'extend' | 'identity' | 'clamp';
extrapolateLeft?: 'extend' | 'identity' | 'clamp';
extrapolateRight?: 'extend' | 'identity' | 'clamp';
}
interface EndResult {
finished: boolean;
}
type EndCallback = (result: EndResult) => void;
type ValueListenerCallback = (state: { value: number }) => void;
type ValueXYListenerCallback = (state: { value: { x: number; y: number } }) => void;
type Mapping = { [key: string]: any } | AnimatedValue | null;
interface EventConfig {
useNativeDriver?: boolean;
listener?: Function;
}Install with Tessl CLI
npx tessl i tessl/npm-react-native-web