React DOM support for the react-spring animation library with spring-physics based animations
—
React hooks for declarative animation control including springs, transitions, trails, and utility hooks. These hooks provide the core animation functionality for @react-spring/web.
Creates a single spring animation with configurable properties and easing.
/**
* Creates a single spring animation
* @param props - Spring configuration and target values
* @returns Spring values for use in animated components
*/
function useSpring<Props extends object>(
props: UseSpringProps<Props>
): SpringValues<PickAnimated<Props>>;
/**
* Creates a spring with function-based props and dependencies
* @param props - Function returning spring configuration
* @param deps - Dependency array for recalculation
* @returns Tuple of spring values and spring ref
*/
function useSpring<Props extends object>(
props: () => UseSpringProps<Props>,
deps?: readonly any[]
): [SpringValues<PickAnimated<Props>>, SpringRef<PickAnimated<Props>>];
interface UseSpringProps<Props extends object = any> extends ControllerUpdate<PickAnimated<Props>> {
/** Reference for imperative control */
ref?: SpringRef<PickAnimated<Props>>;
}Usage Examples:
import { useSpring, animated } from "@react-spring/web";
// Basic spring animation
function FadeIn() {
const styles = useSpring({
from: { opacity: 0 },
to: { opacity: 1 },
config: { duration: 1000 }
});
return <animated.div style={styles}>Content</animated.div>;
}
// Function-based with dependencies
function ConditionalSpring({ show }) {
const [styles, api] = useSpring(() => ({
opacity: show ? 1 : 0,
transform: show ? 'translateY(0px)' : 'translateY(-50px)'
}), [show]);
return <animated.div style={styles}>Conditional content</animated.div>;
}Creates multiple spring animations with individual configurations.
/**
* Creates multiple spring animations
* @param length - Number of springs to create
* @param props - Configuration for each spring
* @returns Array of spring values
*/
function useSprings<Props extends object>(
length: number,
props: UseSpringProps<Props>[] | ((index: number) => UseSpringProps<Props>)
): SpringValues<PickAnimated<Props>>[];
/**
* Creates multiple springs with function-based props and dependencies
* @param length - Number of springs to create
* @param props - Function returning spring configurations
* @param deps - Dependency array for recalculation
* @returns Tuple of spring values array and spring ref
*/
function useSprings<Props extends object>(
length: number,
props: () => UseSpringProps<Props>[] | ((index: number) => UseSpringProps<Props>),
deps?: readonly any[]
): [SpringValues<PickAnimated<Props>>[], SpringRef<PickAnimated<Props>>];Usage Examples:
// Multiple springs with different configs
function MultipleBoxes({ items }) {
const springs = useSprings(items.length, items.map((item, index) => ({
from: { opacity: 0, transform: 'translateX(-100px)' },
to: { opacity: 1, transform: 'translateX(0px)' },
delay: index * 100,
})));
return springs.map((styles, index) => (
<animated.div key={index} style={styles}>
{items[index]}
</animated.div>
));
}Creates staggered spring animations that follow each other in sequence.
/**
* Creates staggered spring animations
* @param length - Number of items in the trail
* @param props - Spring configuration applied to all items
* @returns Array of spring values with staggered timing
*/
function useTrail<Props extends object>(
length: number,
props: UseTrailProps<Props>
): SpringValues<PickAnimated<Props>>[];
/**
* Creates trail with function-based props and dependencies
* @param length - Number of items in the trail
* @param props - Function returning spring configuration
* @param deps - Dependency array for recalculation
* @returns Tuple of spring values array and spring ref
*/
function useTrail<Props extends object>(
length: number,
props: () => UseTrailProps<Props>,
deps?: readonly any[]
): [SpringValues<PickAnimated<Props>>[], SpringRef<PickAnimated<Props>>];
type UseTrailProps<Props extends object = any> = UseSpringProps<Props>;Usage Examples:
// Staggered list animation
function StaggeredList({ words }) {
const trails = useTrail(words.length, {
from: { opacity: 0, transform: 'translateY(20px)' },
to: { opacity: 1, transform: 'translateY(0px)' },
});
return trails.map((styles, index) => (
<animated.div key={index} style={styles}>
{words[index]}
</animated.div>
));
}Animates list transitions with enter, update, and leave phases.
/**
* Animates list transitions with enter/update/leave phases
* @param data - Array of items to transition
* @param props - Transition configuration
* @returns Transition function for rendering items
*/
function useTransition<Item, Props extends object>(
data: OneOrMore<Item>,
props: UseTransitionProps<Item, Props>
): TransitionFn<Item, PickAnimated<Props>>;
/**
* Creates transition with function-based props and dependencies
* @param data - Array of items to transition
* @param props - Function returning transition configuration
* @param deps - Dependency array for recalculation
* @returns Tuple of transition function and spring ref
*/
function useTransition<Item, Props extends object>(
data: OneOrMore<Item>,
props: () => UseTransitionProps<Item, Props>,
deps?: readonly any[]
): [TransitionFn<Item, PickAnimated<Props>>, SpringRef<PickAnimated<Props>>];
interface UseTransitionProps<Item, Props extends object = any> {
/** Animation when items enter */
from?: TransitionTo<Item, PickAnimated<Props>>;
/** Animation when items first appear or update */
enter?: TransitionTo<Item, PickAnimated<Props>>;
/** Animation when items update */
update?: TransitionTo<Item, PickAnimated<Props>>;
/** Animation when items leave */
leave?: TransitionTo<Item, PickAnimated<Props>>;
/** Key function for item identification */
keys?: ItemKeys<Item>;
/** Animation configuration */
config?: SpringConfig | ((item: Item, state: string) => SpringConfig);
/** Delay before animation starts */
delay?: number;
/** Animation trail delay between items */
trail?: number;
}
type TransitionFn<Item, State extends Lookup> = (
style: SpringValues<State>,
item: Item,
transition: TransitionState<Item>,
index: number
) => React.ReactElement;Usage Examples:
// List transitions
function TodoList({ todos }) {
const transitions = useTransition(todos, {
from: { opacity: 0, height: 0 },
enter: { opacity: 1, height: 'auto' },
leave: { opacity: 0, height: 0 },
keys: todo => todo.id,
});
return transitions((style, todo) => (
<animated.div style={style}>
{todo.text}
</animated.div>
));
}
// Modal transitions
function Modal({ show, children }) {
const transitions = useTransition(show, {
from: { opacity: 0, transform: 'scale(0.9)' },
enter: { opacity: 1, transform: 'scale(1)' },
leave: { opacity: 0, transform: 'scale(0.9)' },
});
return transitions((style, item) =>
item ? (
<animated.div style={style}>
{children}
</animated.div>
) : null
);
}Chains multiple spring animations to run in sequence.
/**
* Chains multiple spring animations to run in sequence
* @param refs - Array of spring refs to chain
* @param timeSteps - Optional timing for each animation (0-1)
* @param timeFrame - Total duration for the entire chain
*/
function useChain(
refs: SpringRef[],
timeSteps?: number[],
timeFrame?: number
): void;Usage Examples:
function ChainedAnimation() {
const [open, setOpen] = useState(false);
const [fadeStyles, fadeApi] = useSpring(() => ({
opacity: open ? 1 : 0
}), []);
const [scaleStyles, scaleApi] = useSpring(() => ({
transform: open ? 'scale(1)' : 'scale(0)'
}), []);
// Chain fade first, then scale
useChain(open ? [fadeApi, scaleApi] : [scaleApi, fadeApi], [0, 0.5], 1000);
return (
<animated.div style={fadeStyles}>
<animated.div style={scaleStyles}>
Chained animation
</animated.div>
</animated.div>
);
}Creates a reference for imperative control of spring animations.
/**
* Creates a reference for imperative spring control
* @returns Spring reference for imperative API calls
*/
function useSpringRef<State extends Lookup = Lookup>(): SpringRef<State>;Creates a single animated value that can be used independently.
/**
* Creates a single animated value
* @param initialValue - Initial value for the spring
* @param props - Optional spring configuration
* @returns SpringValue instance
*/
function useSpringValue<T>(
initialValue: T,
props?: SpringUpdate<T>
): SpringValue<T>;Usage Examples:
function IndependentValue() {
const opacity = useSpringValue(0, { config: { tension: 300 } });
const handleClick = () => {
opacity.start(opacity.get() === 0 ? 1 : 0);
};
return (
<animated.div
style={{ opacity }}
onClick={handleClick}
>
Click to toggle
</animated.div>
);
}Additional hooks for specific use cases.
/**
* Creates scroll-based animations
* @param props - Scroll animation configuration
* @returns Spring values responding to scroll events
*/
function useScroll(props?: UseScrollProps): SpringValues<ScrollData>;
/**
* Creates resize-based animations
* @param props - Resize animation configuration
* @returns Spring values responding to resize events
*/
function useResize(props?: UseResizeProps): SpringValues<ResizeData>;
/**
* Creates intersection observer-based animations
* @param props - InView animation configuration
* @returns Tuple of spring values and ref to observe
*/
function useInView(props?: UseInViewProps): [SpringValues<InViewData>, React.RefObject<Element>];React components providing declarative alternatives to animation hooks.
Declarative component for single spring animations using render props pattern.
/**
* Declarative spring animation component
* @param props - Spring configuration with children render prop
* @returns JSX element from children function
*/
function Spring<State extends object>(
props: SpringComponentProps<State>
): JSX.Element | null;
interface SpringComponentProps<State extends object> extends UseSpringProps<State> {
/** Render prop function receiving spring values */
children: (values: SpringValues<State>) => React.JSX.Element | null;
}Usage Examples:
import { Spring } from "@react-spring/web";
function DeclarativeSpring() {
return (
<Spring
from={{ opacity: 0 }}
to={{ opacity: 1 }}
config={{ duration: 1000 }}
>
{styles => <div style={styles}>Animated content</div>}
</Spring>
);
}Declarative component for staggered trail animations using render props pattern.
/**
* Declarative trail animation component
* @param props - Trail configuration with children render prop
* @returns JSX element from children function
*/
function Trail<State extends object>(
props: TrailComponentProps<State>
): JSX.Element | null;
interface TrailComponentProps<State extends object> extends UseTrailProps<State> {
/** Number of items in the trail */
length: number;
/** Render prop function receiving array of spring values */
children: (values: SpringValues<State>[]) => React.JSX.Element | null;
}Usage Examples:
import { Trail } from "@react-spring/web";
function DeclarativeTrail({ items }) {
return (
<Trail
length={items.length}
from={{ opacity: 0, transform: 'translateY(20px)' }}
to={{ opacity: 1, transform: 'translateY(0px)' }}
>
{trails => (
<div>
{trails.map((style, index) => (
<div key={index} style={style}>
{items[index]}
</div>
))}
</div>
)}
</Trail>
);
}Declarative component for list transitions using render props pattern.
/**
* Declarative transition animation component
* @param props - Transition configuration with children render prop
* @returns JSX element from children function
*/
function Transition<Item, State extends object>(
props: TransitionComponentProps<Item, State>
): JSX.Element | null;
interface TransitionComponentProps<Item, State extends object> extends UseTransitionProps<Item, State> {
/** Array of items to transition */
items: OneOrMore<Item>;
/** Render prop function receiving transition function */
children: (transitionFn: TransitionFn<Item, State>) => React.JSX.Element | null;
}Usage Examples:
import { Transition } from "@react-spring/web";
function DeclarativeTransition({ todos }) {
return (
<Transition
items={todos}
from={{ opacity: 0, height: 0 }}
enter={{ opacity: 1, height: 'auto' }}
leave={{ opacity: 0, height: 0 }}
keys={todo => todo.id}
>
{transitions => (
<div>
{transitions((style, todo) => (
<div style={style}>{todo.text}</div>
))}
</div>
)}
</Transition>
);
}Creates scroll-linked animations that respond to window or element scroll position.
/**
* Creates scroll-linked animations
* @param options - Configuration including optional container ref
* @returns Spring values with scroll progress and position
*/
function useScroll(
options?: UseScrollOptions
): SpringValues<{
scrollX: number;
scrollY: number;
scrollXProgress: number;
scrollYProgress: number;
}>;
interface UseScrollOptions extends Omit<SpringProps, 'to' | 'from'> {
/** Container element to observe (defaults to window) */
container?: MutableRefObject<HTMLElement>;
}Usage Examples:
import { useScroll, animated } from "@react-spring/web";
// Window scroll progress
function ScrollIndicator() {
const { scrollYProgress } = useScroll();
return (
<animated.div
style={{
transform: scrollYProgress.to(y => `scaleX(${y})`)
}}
/>
);
}
// Element scroll tracking
function ScrollContainer() {
const containerRef = useRef<HTMLDivElement>(null);
const { scrollY } = useScroll({ container: containerRef });
return (
<div ref={containerRef} style={{ height: 300, overflow: 'auto' }}>
<animated.div style={{ transform: scrollY.to(y => `translateY(${y}px)`) }}>
Scroll content
</animated.div>
</div>
);
}Creates animations based on element or window resize events.
/**
* Creates resize-responsive animations
* @param options - Configuration including optional container ref
* @returns Spring values with width and height
*/
function useResize(
options?: UseResizeOptions
): SpringValues<{
width: number;
height: number;
}>;
interface UseResizeOptions extends Omit<SpringProps, 'to' | 'from'> {
/** Container element to observe (defaults to window) */
container?: MutableRefObject<HTMLElement | null | undefined>;
}Usage Examples:
import { useResize, animated } from "@react-spring/web";
// Window resize responsive
function ResponsiveBox() {
const { width, height } = useResize();
return (
<animated.div
style={{
width: width.to(w => w * 0.8),
height: height.to(h => h * 0.6)
}}
/>
);
}
// Element resize tracking
function ResizableContainer() {
const containerRef = useRef<HTMLDivElement>(null);
const { width } = useResize({ container: containerRef });
return (
<div ref={containerRef}>
<animated.div style={{ fontSize: width.to(w => w / 20) }}>
Scalable text
</animated.div>
</div>
);
}Creates animations triggered by element intersection with viewport.
/**
* Creates intersection observer animations
* @param args - Intersection observer configuration
* @returns Tuple of element ref and boolean in-view state
*/
function useInView(args?: IntersectionArgs): [RefObject<any>, boolean];
/**
* Creates intersection observer animations with spring values
* @param props - Function returning spring configuration
* @param args - Intersection observer configuration
* @returns Tuple of element ref and spring values
*/
function useInView<Props extends object>(
props: () => Props & Valid<Props, UseSpringProps<Props>>,
args?: IntersectionArgs
): [RefObject<any>, SpringValues<PickAnimated<Props>>];
interface IntersectionArgs extends Omit<IntersectionObserverInit, 'root' | 'threshold'> {
/** Root element for intersection (defaults to viewport) */
root?: React.MutableRefObject<HTMLElement>;
/** Trigger animation only once */
once?: boolean;
/** Intersection amount trigger: 'any', 'all', number, or array */
amount?: 'any' | 'all' | number | number[];
}Usage Examples:
import { useInView, animated } from "@react-spring/web";
// Basic visibility detection
function FadeInOnScroll() {
const [ref, inView] = useInView();
return (
<div ref={ref}>
{inView ? 'Visible!' : 'Not visible'}
</div>
);
}
// Animated entrance on scroll
function AnimatedOnScroll() {
const [ref, springs] = useInView(
() => ({
from: { opacity: 0, y: 50 },
to: { opacity: 1, y: 0 },
}),
{ once: true }
);
return (
<animated.div ref={ref} style={springs}>
Fade in when scrolled into view
</animated.div>
);
}
// Custom intersection threshold
function PartiallyVisible() {
const [ref, springs] = useInView(
() => ({
from: { scale: 0.8 },
to: { scale: 1 },
}),
{ amount: 0.5 } // Trigger when 50% visible
);
return (
<animated.div ref={ref} style={springs}>
Scales when half visible
</animated.div>
);
}interface SpringConfig {
/** Animation duration in milliseconds */
duration?: number;
/** Spring tension (stiffness) */
tension?: number;
/** Spring friction (damping) */
friction?: number;
/** Mass of the spring */
mass?: number;
/** Precision threshold for stopping */
precision?: number;
/** Velocity threshold for stopping */
velocity?: number;
/** Animation easing function */
easing?: EasingFunction;
/** Clamp values to prevent overshoot */
clamp?: boolean;
}Install with Tessl CLI
npx tessl i tessl/npm-react-spring--web