Skip to content
Browser

useAnimate

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

Web Animations API
idle

Reactive wrapper around element.animate() with play / pause / reverse controls.

playState
idle
currentTime
playbackRate
1x
pending
false
import {
const useRef$: {
<T = any>(initialValue: null): Ref$<T | null>;
<T = any>(initialValue: T): Ref$<T>;
<T = any>(): Ref$<T | null>;
}
useRef$
} from "@usels/core";
import {
const useAnimate: (target: MaybeEventTarget, keyframes: UseAnimateKeyframes, options?: number | DeepMaybeObservable<UseAnimateOptions>) => UseAnimateReturn
useAnimate
} from "@usels/web";
function
function Component(): JSX.Element
Component
() {
const
const el$: Ref$<HTMLSpanElement | null>
el$
=
useRef$<HTMLSpanElement>(): Ref$<HTMLSpanElement | null> (+2 overloads)

Core (framework-agnostic) version of useRef$. Creates an observable element ref with opaque wrapping.

  • non-null value → Ref$<T>: current, get(), peek() return T
  • null / no arg → Ref$<T | null>: current, get(), peek() return T | null

Nullability is expressed via the type parameter, mirroring T | null at the call site.

useRef$
<
interface HTMLSpanElement
HTMLSpanElement
>();
const {
const playState$: ReadonlyObservable<AnimationPlayState>
playState$
,
const play: Fn
play
,
const pause: Fn
pause
} =
function useAnimate(target: MaybeEventTarget, keyframes: UseAnimateKeyframes, options?: number | DeepMaybeObservable<UseAnimateOptions>): UseAnimateReturn

Framework-agnostic reactive wrapper around the Web Animations API.

Must be called inside a useScope factory — resource setup (update) is registered via onMount and cleanup via onUnmount. rAF sync, element tracking, keyframe reactivity, and animation-event listening are all driven by scope-aware observe() so the whole pipeline tears down on scope disposal.

useAnimate
(
const el$: Ref$<HTMLSpanElement | null>
el$
,
{
transform: string
transform
: "rotate(360deg)" },
1000
);
return (
<
JSX.IntrinsicElements.div: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>
<
JSX.IntrinsicElements.span: DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>
span
RefAttributes<HTMLSpanElement>.ref?: 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 | null>
el$
}
HTMLAttributes<HTMLSpanElement>.style?: 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</
JSX.IntrinsicElements.span: DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>
span
>
<
JSX.IntrinsicElements.p: DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
>{
const playState$: ReadonlyObservable<AnimationPlayState>
playState$
.
ImmutableObservableBase<AnimationPlayState>.get(trackingType?: TrackingType | GetOptions): any
get
()}</
JSX.IntrinsicElements.p: DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
>
<
JSX.IntrinsicElements.button: DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button
DOMAttributes<HTMLButtonElement>.onClick?: MouseEventHandler<HTMLButtonElement> | undefined
onClick
={
const play: Fn
play
}>Play</
JSX.IntrinsicElements.button: DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button
>
<
JSX.IntrinsicElements.button: DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button
DOMAttributes<HTMLButtonElement>.onClick?: MouseEventHandler<HTMLButtonElement> | undefined
onClick
={
const pause: Fn
pause
}>Pause</
JSX.IntrinsicElements.button: DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button
>
</
JSX.IntrinsicElements.div: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>
);
}

Array, object, or Observable keyframes are all supported.

import { useRef$ } from "@usels/core";
import { useAnimate } from "@usels/web";
import { useObservable } from "@usels/core";
function Component() {
const el$ = useRef$<HTMLDivElement>();
// Object form (PropertyIndexedKeyframes)
useAnimate(el$, { transform: "rotate(360deg)" }, 1000);
// Array form
useAnimate(el$, [{ transform: "rotate(0deg)" }, { transform: "rotate(360deg)" }], 1000);
// Observable — effect updates when value changes
const keyframes$ = useObservable([
{ clipPath: "circle(20% at 0% 30%)" },
{ clipPath: "circle(20% at 50% 80%)" },
]);
useAnimate(el$, 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 { useRef$ } from "@usels/core";
import { useAnimate } from "@usels/web";
function Component() {
const el$ = useRef$<HTMLDivElement>();
const { play } = useAnimate(
el$,
{ opacity: [0, 1] },
{
duration: 1000,
immediate: false,
}
);
return (
<>
<div ref={el$} />
<button onClick={play}>Start Animation</button>
</>
);
}
ParameterTypeDescription
targetMaybeEventTarget-
keyframesUseAnimateKeyframes-
optionsnumber | DeepMaybeObservable<UseAnimateOptions> | undefined (optional)-
OptionTypeDefaultDescription
immediatebooleantrueStart playing immediately on mount.
commitStylesbooleanfalseCommit final styles to the element on finish.
persistbooleanfalsePersist the animation.
playbackRatenumber1Initial playback rate.
onReady((animate: Animation) => void)-Called once the Animation instance is ready.
onError((e: unknown) => void)-Called when an animation error occurs.
idstring--
timelineAnimationTimeline | null--
compositeCompositeOperation--
iterationCompositeIterationCompositeOperation--
pseudoElementstring | null--
delaynumber--
directionPlaybackDirection--
durationstring | number | CSSNumericValue--
easingstring--
endDelaynumber--
fillFillMode--
iterationStartnumber--
iterationsnumber--
windowWindowSource--

UseAnimateReturn

NameTypeDescription
animate$ReadonlyObservable<Animation | null>Current Animation instance.
playFn-
pauseFn-
reverseFn-
finishFn-
cancelFn-
pending$ReadonlyObservable<boolean>-
playState$ReadonlyObservable<AnimationPlayState>-
replaceState$ReadonlyObservable<AnimationReplaceState>-
startTime$ObservablePrimitive<number | null>-
currentTime$ObservablePrimitive<number | null>-
timeline$Observable<AnimationTimeline | null>-
playbackRate$ObservablePrimitive<number>-
isSupported$ReadonlyObservable<boolean>-

View on GitHub