Skip to content

useAnimate

Reactive Web Animations API wrapper. Drives element.animate() with Observable-based reactive state for playState, currentTime, playbackRate, and pending.

playState: idle
currentTime: null
playbackRate: 1
pending: false
import {
function useRef$<T extends Element = Element>(externalRef?: React.Ref<T> | null): Ref$<T>

Creates an observable element ref. Can be used as a drop-in replacement for useRef, composed with callback refs, or used with forwardRef.

The element is wrapped with opaqueObject to prevent legendapp/state from making DOM properties reactive (deep observation).

@paramexternalRef - Optional. Accepts callback ref, RefObject, or null (forwardRef compatible).

@returnsA callable ref that is also observable via get/peek

@example

// standalone — useRef replacement
const el$ = useRef$<HTMLDivElement>();
return <div ref={el$} />;
// forwardRef compatible
const Component = forwardRef<HTMLDivElement>((props, ref) => {
const el$ = useRef$(ref);
return <div ref={el$} />;
});
// callback ref composition
const myRef = useCallback((node: HTMLDivElement | null) => {
node?.focus();
}, []);
const el$ = useRef$(myRef);
return <div ref={el$} />;

useRef$
} from "@usels/core";
import {
import useAnimate
useAnimate
} from "@usels/core";
function
function MyComponent(): React.JSX.Element
MyComponent
() {
const
const el$: Ref$<HTMLSpanElement>
el$
=
useRef$<HTMLSpanElement>(externalRef?: React.Ref<HTMLSpanElement> | undefined): Ref$<HTMLSpanElement>

Creates an observable element ref. Can be used as a drop-in replacement for useRef, composed with callback refs, or used with forwardRef.

The element is wrapped with opaqueObject to prevent legendapp/state from making DOM properties reactive (deep observation).

@paramexternalRef - Optional. Accepts callback ref, RefObject, or null (forwardRef compatible).

@returnsA callable ref that is also observable via get/peek

@example

// standalone — useRef replacement
const el$ = useRef$<HTMLDivElement>();
return <div ref={el$} />;
// forwardRef compatible
const Component = forwardRef<HTMLDivElement>((props, ref) => {
const el$ = useRef$(ref);
return <div ref={el$} />;
});
// callback ref composition
const myRef = useCallback((node: HTMLDivElement | null) => {
node?.focus();
}, []);
const el$ = useRef$(myRef);
return <div ref={el$} />;

useRef$
<
interface HTMLSpanElement
HTMLSpanElement
>();
const {
const isSupported$: any
isSupported$
,
const animate$: any
animate$
,
const play: any
play
,
const pause: any
pause
,
const reverse: any
reverse
,
const finish: any
finish
,
const cancel: any
cancel
,
const pending$: any
pending$
,
const playState$: any
playState$
,
const replaceState$: any
replaceState$
,
const startTime$: any
startTime$
,
const currentTime$: any
currentTime$
,
const timeline$: any
timeline$
,
const playbackRate$: any
playbackRate$
,
} =
import useAnimate
useAnimate
(
const el$: Ref$<HTMLSpanElement>
el$
, {
transform: string
transform
: "rotate(360deg)" }, 1000);
return (
<
React.JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>
span
React.RefAttributes<HTMLSpanElement>.ref?: React.Ref<HTMLSpanElement> | undefined

Allows getting a ref to the component instance. Once the component unmounts, React will set ref.current to null (or call the ref with null if you passed a callback ref).

ref
={
const el$: Ref$<HTMLSpanElement>
el$
}
React.HTMLAttributes<HTMLSpanElement>.style?: React.CSSProperties | undefined
style
={{
StandardLonghandProperties<string | number, string & {}>.display?: Property.Display | undefined

This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.

Syntax: [ <display-outside> || <display-inside> ] | <display-listitem> | <display-internal> | <display-box> | <display-legacy>

Initial value: inline

| Chrome | Firefox | Safari | Edge | IE | | :----: | :-----: | :----: | :----: | :---: | | 1 | 1 | 1 | 12 | 4 |

display
: "inline-block" }}>
useAnimate
</
React.JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>
span
>
);
}

Array, object, or Observable keyframes are all supported.

import {
function useRef$<T extends Element = Element>(externalRef?: React.Ref<T> | null): Ref$<T>

Creates an observable element ref. Can be used as a drop-in replacement for useRef, composed with callback refs, or used with forwardRef.

The element is wrapped with opaqueObject to prevent legendapp/state from making DOM properties reactive (deep observation).

@paramexternalRef - Optional. Accepts callback ref, RefObject, or null (forwardRef compatible).

@returnsA callable ref that is also observable via get/peek

@example

// standalone — useRef replacement
const el$ = useRef$<HTMLDivElement>();
return <div ref={el$} />;
// forwardRef compatible
const Component = forwardRef<HTMLDivElement>((props, ref) => {
const el$ = useRef$(ref);
return <div ref={el$} />;
});
// callback ref composition
const myRef = useCallback((node: HTMLDivElement | null) => {
node?.focus();
}, []);
const el$ = useRef$(myRef);
return <div ref={el$} />;

useRef$
} from "@usels/core";
import {
import useAnimate
useAnimate
} from "@usels/core";
import {
function observable<T>(): Observable<T | undefined> (+2 overloads)
observable
} from "@legendapp/state";
function
function MyComponent(): void
MyComponent
() {
const
const el$: Ref$<HTMLDivElement>
el$
=
useRef$<HTMLDivElement>(externalRef?: React.Ref<HTMLDivElement> | undefined): Ref$<HTMLDivElement>

Creates an observable element ref. Can be used as a drop-in replacement for useRef, composed with callback refs, or used with forwardRef.

The element is wrapped with opaqueObject to prevent legendapp/state from making DOM properties reactive (deep observation).

@paramexternalRef - Optional. Accepts callback ref, RefObject, or null (forwardRef compatible).

@returnsA callable ref that is also observable via get/peek

@example

// standalone — useRef replacement
const el$ = useRef$<HTMLDivElement>();
return <div ref={el$} />;
// forwardRef compatible
const Component = forwardRef<HTMLDivElement>((props, ref) => {
const el$ = useRef$(ref);
return <div ref={el$} />;
});
// callback ref composition
const myRef = useCallback((node: HTMLDivElement | null) => {
node?.focus();
}, []);
const el$ = useRef$(myRef);
return <div ref={el$} />;

useRef$
<
interface HTMLDivElement
HTMLDivElement
>();
// Object form (PropertyIndexedKeyframes)
import useAnimate
useAnimate
(
const el$: Ref$<HTMLDivElement>
el$
, {
transform: string
transform
: "rotate(360deg)" }, 1000);
// Array form
import useAnimate
useAnimate
(
const el$: Ref$<HTMLDivElement>
el$
, [{
transform: string
transform
: "rotate(0deg)" }, {
transform: string
transform
: "rotate(360deg)" }], 1000);
// Observable — effect updates when value changes
const
const keyframes$: any
keyframes$
=
observable<unknown>(value: Promise<unknown> | (() => unknown) | unknown): any (+2 overloads)
observable
([
{
clipPath: string
clipPath
: "circle(20% at 0% 30%)" },
{
clipPath: string
clipPath
: "circle(20% at 50% 80%)" },
]);
import useAnimate
useAnimate
(
const el$: Ref$<HTMLDivElement>
el$
,
const keyframes$: any
keyframes$
, 1000);
}

Pass a number as duration shorthand, or an options object with full configuration.

useAnimate(el$, keyframes, {
duration: 1000,
immediate: true, // auto-play on mount (default: true)
commitStyles: false, // commit styles on finish (default: false)
persist: false, // persist animation (default: false)
onReady(animate) {
console.log("ready", animate);
},
onError(e) {
console.error(e);
},
});
import {
function useRef$<T extends Element = Element>(externalRef?: React.Ref<T> | null): Ref$<T>

Creates an observable element ref. Can be used as a drop-in replacement for useRef, composed with callback refs, or used with forwardRef.

The element is wrapped with opaqueObject to prevent legendapp/state from making DOM properties reactive (deep observation).

@paramexternalRef - Optional. Accepts callback ref, RefObject, or null (forwardRef compatible).

@returnsA callable ref that is also observable via get/peek

@example

// standalone — useRef replacement
const el$ = useRef$<HTMLDivElement>();
return <div ref={el$} />;
// forwardRef compatible
const Component = forwardRef<HTMLDivElement>((props, ref) => {
const el$ = useRef$(ref);
return <div ref={el$} />;
});
// callback ref composition
const myRef = useCallback((node: HTMLDivElement | null) => {
node?.focus();
}, []);
const el$ = useRef$(myRef);
return <div ref={el$} />;

useRef$
} from "@usels/core";
import {
import useAnimate
useAnimate
} from "@usels/core";
function
function MyComponent(): React.JSX.Element
MyComponent
() {
const
const el$: Ref$<HTMLDivElement>
el$
=
useRef$<HTMLDivElement>(externalRef?: React.Ref<HTMLDivElement> | undefined): Ref$<HTMLDivElement>

Creates an observable element ref. Can be used as a drop-in replacement for useRef, composed with callback refs, or used with forwardRef.

The element is wrapped with opaqueObject to prevent legendapp/state from making DOM properties reactive (deep observation).

@paramexternalRef - Optional. Accepts callback ref, RefObject, or null (forwardRef compatible).

@returnsA callable ref that is also observable via get/peek

@example

// standalone — useRef replacement
const el$ = useRef$<HTMLDivElement>();
return <div ref={el$} />;
// forwardRef compatible
const Component = forwardRef<HTMLDivElement>((props, ref) => {
const el$ = useRef$(ref);
return <div ref={el$} />;
});
// callback ref composition
const myRef = useCallback((node: HTMLDivElement | null) => {
node?.focus();
}, []);
const el$ = useRef$(myRef);
return <div ref={el$} />;

useRef$
<
interface HTMLDivElement
HTMLDivElement
>();
const {
const play: any
play
} =
import useAnimate
useAnimate
(
const el$: Ref$<HTMLDivElement>
el$
,
{
opacity: {}
opacity
: [0, 1] },
{
duration: number
duration
: 1000,
immediate: boolean
immediate
: false,
}
);
return <
React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button
React.DOMAttributes<HTMLButtonElement>.onClick?: React.MouseEventHandler<HTMLButtonElement> | undefined
onClick
={
const play: any
play
}>Start Animation</
React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button
>;
}
export interface UseAnimateOptions extends KeyframeAnimationOptions, ConfigurableWindow {
immediate?: boolean;
commitStyles?: boolean;
persist?: boolean;
playbackRate?: number;
onReady?: (animate: Animation) => void;
onError?: (e: unknown) => void;
}
export type UseAnimateKeyframes = MaybeObservable<Keyframe[] | PropertyIndexedKeyframes | null>;
export interface UseAnimateReturn {
isSupported$: ReadonlyObservable<boolean>;
animate$: ReadonlyObservable<Animation | null>;
play: Fn;
pause: Fn;
reverse: Fn;
finish: Fn;
cancel: Fn;
pending$: ReadonlyObservable<boolean>;
playState$: ReadonlyObservable<AnimationPlayState>;
replaceState$: ReadonlyObservable<AnimationReplaceState>;
startTime$: Observable<number | null>;
currentTime$: Observable<number | null>;
timeline$: Observable<AnimationTimeline | null>;
playbackRate$: Observable<number>;
}
export declare function useAnimate(target: MaybeElement, keyframes: UseAnimateKeyframes, options?: number | DeepMaybeObservable<UseAnimateOptions>): UseAnimateReturn;

View on GitHub

  • tigerwest
  • a7392ab 2026-03-06 - feat(core,browser): add sync strategy hooks (tigerwest)