Skip to content

JS API

Animate the component's root element with Motion.

Options

Object options are parsed as JSON: quote the keys (data-option-animate='{ "x": 100 }'). The available keyframes and transition settings are Motion's own — see the animate() documentation for the full vocabulary.

initial

  • Type: DOMKeyframesDefinition
  • Default: {}

Styles applied to the element on mount, before anything plays. Use it to define the starting state of an enter animation without a flash of the final state. It doubles as the starting point of the animate keyframes, so the declared animation always plays from here — however many times it runs.

html
<div
  data-component="Motion"
  data-option-initial='{ "opacity": 0, "y": 24 }'
  data-option-animate='{ "opacity": 1, "y": 0 }'>

</div>

animate

  • Type: DOMKeyframesDefinition
  • Default: {}

The target keyframes of the animation. They play on mount when autoplay is enabled.

Each property the initial option also describes starts from that style, so the declared animation replays identically for as long as the options stand — declare the starting state once, in initial:

html
<div
  data-component="Motion"
  data-option-initial='{ "opacity": 0, "y": 24 }'
  data-option-animate='{ "opacity": 1, "y": 0 }'
  data-option-autoplay>

</div>

A property initial says nothing about animates from whatever the element currently shows, which is what a one-off transition to a new state wants. To pin a starting point without painting it on mount, write that property as a [from, to] array ({ "opacity": [0.2, 1] }) — an explicit array is never overridden.

transition

  • Type: AnimationOptions
  • Default: {}

Motion's animation options: duration, delay, ease, type ("tween", "spring", "inertia"), repeat, spring physics, etc.

html
<div
  data-component="Motion"
  data-option-animate='{ "scale": 1 }'
  data-option-transition='{ "type": "spring", "bounce": 0.3 }'>

</div>

autoplay

  • Type: boolean
  • Default: false

Whether the animate keyframes play automatically on mount. Enable it with the data-option-autoplay attribute; without it, playback waits for an explicit play().

html
<div
  data-component="Motion"
  data-option-animate='{ "x": 100 }'
  data-option-autoplay>

</div>

hover

  • Type: DOMKeyframesDefinition
  • Default: {}

Keyframes applied while the element is hovered, through Motion's hover() — real hover only, touch emulation is filtered out. When the hover ends, a new animation plays forward to the base values of the properties the gesture touched, with the same transition — the same return Motion for React performs when it deactivates a whileHover variant. The base value of each property is read from the element once, the first time a gesture touches it, so the return never plays the easing or spring curve backward and never depends on a gesture animation still being around.

html
<div
  data-component="Motion"
  data-option-hover='{ "scale": 1.1 }'>

</div>

press

  • Type: DOMKeyframesDefinition
  • Default: {}

Keyframes applied while the element is pressed, through Motion's press() — pointer and keyboard alike, so the state is accessible for free. Returns to the base values like hover when the press ends.

inView

  • Type: DOMKeyframesDefinition
  • Default: {}

Keyframes applied when the element enters the viewport, through Motion's inView(). Returns to the base values when the element leaves, unless once is set. Declaring initial is the way to choose those base values: it is applied on mount, so it is what the element holds when the first reveal reads it.

html
<div
  data-component="Motion"
  data-option-initial='{ "opacity": 0, "y": 24 }'
  data-option-in-view='{ "opacity": 1, "y": 0 }'
  data-option-once>

</div>

inViewMargin

  • Type: string
  • Default: ''

The viewport margin for the inView detection, in CSS margin syntax (e.g. "-100px" to trigger 100px inside the viewport).

inViewAmount

  • Type: 'some' | 'all' | number
  • Default: 'some'

How much of the element must be visible to trigger inView: "some", "all", or a 01 proportion.

once

  • Type: boolean
  • Default: false

When set, the inView keyframes play once and the reached styles persist — the element is no longer watched.

Gesture animations are transient

The gesture options animate alongside the declared animation: they never become the current animation and emit no lifecycle events — and neither does the animation returning to the base values. Like scroll(), the gesture functions are not part of motion/mini — a gesture option warns and is skipped when the provided module lacks its function.

Events

All events are dispatched as bubbling CustomEvents on the component's element, so they can be listened to with Action's data-on:<event> attribute — either on the same element or on an ancestor. Use the .stop modifier to contain them.

EventFired when
motion-playa playback starts (autoplay, play(), reverse() or animate()).
motion-pausethe current animation is paused.
motion-completethe current animation finishes.
motion-stopthe current animation is stopped, keeping the styles it reached.
motion-cancelthe current animation is cancelled, reverting to the pre-animation styles.
html
<div
  data-component="Action Motion"
  data-option-animate='{ "opacity": 1 }'
  data-on:motion-complete="console.log('done')">

</div>

Methods

The component holds a single current animation. play() and reverse() always drive the animation declared by the options — recreating it when an imperative animate() call superseded it — while pause(), seek(), stop(), cancel() and complete() act on whichever animation is current. play(), reverse() and animate() return a promise that resolves when the animation settles and never rejects.

MethodDescription
play()Play the declared animation forward, creating it on first play. Restarts a finished animation.
reverse()Play the declared animation backward. When nothing has played yet, it starts from its end.
pause()Pause the current animation in place.
seek(progress)Jump to a progress between 0 and 1, creating the declared animation paused when nothing has played yet.
animate(keyframes, options)Run a one-off animation to arbitrary keyframes; options are merged over transition. play() returns to the declared animation.
stop()Stop the current animation and commit the styles reached. The next play() creates a fresh animation.
cancel()Cancel the current animation and revert to the pre-animation styles. The next play() creates a fresh animation.
complete()Jump the current animation to its end state.

Methods are callable from an Action effect — on the same element or through the target syntax:

html
<div data-component="Action" data-on:mouseenter="Motion(#logo)->target.play()"
  data-on:mouseleave="Motion(#logo)->target.reverse()">
  <div id="logo" data-component="Motion" data-option-animate='{ "scale": 1.2 }'>…</div>
</div>

Getters

GetterDescription
controlsThe current Motion playback controls, or null when idle.
timeThe current playback time in seconds.
durationThe current animation duration in seconds.
progressThe current playback progress, from 0 to 1.

Providing the Motion dependency

By default the component resolves motion with a lazy import() the first time an animation is built. To control which build is used — a specific version, the smaller motion/mini entry, or a module served from an import map or a CDN — inject it once with provideMotion() before the components mount:

js
import { animate } from 'motion/mini';
import { provideMotion } from '@studiometa/ui-motion';

provideMotion({ animate });

Once provided, @studiometa/ui-motion never imports motion by specifier — it uses the instance you handed it. The injected value must satisfy the MotionModule type: the subset of the motion module the components consume. resolveMotion() is also exported to trigger (and await) resolution yourself, for example to preload the module.