Skip to content

JavaScript API

init(options?)

Finds every element possessing data-mos and sets up scroll tracking for them. Call this once on page load after registering any additional presets desired.

import { MOS } from 'motion-on-scroll';
MOS.init({
offset: 200,
duration: 600,
easing: 'ease-out',
once: true
});

Type: number (pixels)
Default: 120

Additional distance (in pixels) before an element is considered in view.

Type: number
Default: 400

Animation duration. (MOS uses the browser’s Web Animations API where possible.)

Type: number
Default: 0

Delay before an element animates in. As in AOS, there is no delay when it animates out.

Type: "ms" | "s"
Default: "ms"

Units for duration and delay.

Type: number (pixels)
Default: 100

Travel distance for directional presets like fade-up.

Type: string
Default: 'ease'

Supports any of these predefined keywords:

  • linear, ease
  • ease-in, ease-out, ease-in-out
  • circ-in, circ-out, circ-in-out
  • back-in, back-out, back-in-out, anticipate
  • ease-in-back, ease-out-back, ease-in-out-back
  • ease-in-sine, ease-out-sine, ease-in-out-sine
  • ease-in-quad, ease-out-quad, ease-in-out-quad
  • ease-in-cubic, ease-out-cubic, ease-in-out-cubic
  • ease-in-quart, ease-out-quart, ease-in-out-quart

You can also pass a custom cubic-bezier string in any of the following formats:

  • cubic-bezier(x1, y1, x2, y2)
  • [x1,y1,x2,y2] or x1,y1,x2,y2

Need something else? Define a custom easing preset with MOS.registerEasing and use it in your presets.

Type: boolean
Default: false

If true, an element animates only once: after it has animated in, it is not reversed or replayed when you scroll back past it.

Type: boolean
Default: false

If true, elements animate when scrolling up as well as down (requires once: false).

Type: boolean | 'mobile' | 'phone' | 'tablet' | (() => boolean)
Default: false

Disable animations entirely under specific conditions (e.g. on mobile).

Type: boolean
Default: false

Skip the automatic MutationObserver (useful when you manage DOM changes manually).

Type: string
Default: "DOMContentLoaded"

DOM event that triggers MOS to start. Defaults to “DOMContentLoaded”.

Type: number
Default: 99

Throttle delay for scroll events in ms.

Type: number
Default: 50

Debounce delay for resize/orientation events in ms.

Type: 'top-bottom' | 'top-center' | 'top-top' | 'center-bottom' | 'center-center' | 'center-top' | 'bottom-bottom' | 'bottom-center' | 'bottom-top'
Default: 'top-bottom'

Which part of the element has to reach which part of the viewport to trigger the animation. Can be overridden per element with data-mos-anchor-placement.

Type: string | false
Default: 'mos-init'

Class added to every element once MOS has prepared it. false disables it.

Type: string | false
Default: 'mos-animate'

Class present on an element while it is animated in. false disables it. The bundled stylesheet re-enables pointer events using the default name.

Type: boolean
Default: false

If true, the value of data-mos is also added to the element as class names while it is animated in.

Type: boolean
Default: true

If true, MOS is disabled (exactly as with disable) for visitors who have asked their system to reduce motion. Set to false to animate regardless.

Calling init() more than once merges the new options into the ones passed earlier.

Recalculates the trigger positions of all tracked elements. Has no effect until the start event has fired.

Re-evaluates the DOM for [data-mos] elements: new elements start being tracked, removed ones are cleaned up, and elements that already animated in stay as they are. Useful after client-side navigation or significant DOM changes. This is called automatically when DOM changes are detected, unless you disable the mutation observer.

Removes every listener and observer and stops tracking all elements, leaving them in whatever visual state they are in. Options from earlier init() calls are forgotten, so MOS can be initialised again from scratch. Useful when tearing down a page in a single-page app.

Like AOS, MOS dispatches events on document when an element animates in or out. event.detail is the element.

document.addEventListener('mos:in', ({ detail }) => {
console.log('animated in', detail);
});
document.addEventListener('mos:out', ({ detail }) => {
console.log('animated out', detail);
});

Give an element a data-mos-id to also receive mos:in:<id> and mos:out:<id> for that element only.

Functions are exposed to allow you to register custom keyframes, easings, or even whole animations for complex use cases.

registerKeyframes(name, definition)

Registers custom keyframes that can subsequently be referenced via the data-mos attribute.

import { MOS } from 'motion-on-scroll';
MOS.registerKeyframes("my-custom-animation", {
opacity: [0, 1],
rotate: [0, 360],
});
// initialize MOS after registering keyframes
MOS.init();
<!-- somewhere in html -->
<div data-mos="my-custom-animation"></div>

Type: string
Unique identifier (case-sensitive). Must be non-empty. Registering a name that already exists replaces it.

Type: DOMKeyframesDefinition
Any keyframes object accepted by motion’s animate function.

registerEasing(name, definition)

Registers a custom easing that can subsequently be referenced via the easing option of MOS.init() or within any data-mos-easing attribute.

import { MOS } from 'motion-on-scroll';
// Register a cubic-bezier array
MOS.registerEasing('bouncy', [0.68, -0.55, 0.265, 1.55]);
// Register a cubic-bezier string (will be parsed)
MOS.registerEasing('custom', 'cubic-bezier(0.25, 0.46, 0.45, 0.94)');
// initialize MOS after registering easings
MOS.init({
easing: 'bouncy',
});
<!-- or somewhere in html -->
<div data-mos="fade-up" data-mos-easing="bouncy"></div>

Type: string
Unique identifier (case-sensitive). Must be non-empty. Registering a name that already exists replaces it.

Type: EasingDefinition | string
Any easing accepted by Motion — named keyword, cubic-bezier array, or cubic-bezier string.

The function validates the input and throws if the easing cannot be parsed.

registerAnimation(name, factory)

Registers a custom animation that can subsequently be referenced via the data-mos attribute. This enables you to completely customize the animation logic using motion’s animate function.

import { MOS } from 'motion-on-scroll';
import { animate } from "motion";
MOS.registerAnimation("bouncy", (el, opts) =>
animate(
el,
{ opacity: [0, 1], scale: [0.4, 1] },
{
type: "spring",
bounce: 0.5,
duration: opts.timeUnits === "s" ? opts.duration : opts.duration / 1000,
},
),
);
// initialize MOS after registering animation
MOS.init();
<!-- somewhere in html -->
<div data-mos="bouncy"></div>

Type: string
Unique identifier (case-sensitive). Must be non-empty.

Type: (el: HTMLElement, opts: ElementOptions) => AnimationPlaybackControls
A factory function that uses motion’s animate function to create an animation.

ElementOptions is an object that contains the merged global options and element-level options (it extends the global MosOptions). It has the following properties which you can use to enable customizable animations via data attributes on individual elements:

interface ElementOptions {
/** Additional px distance before an element is considered in view */
offset: number;
/** Animation duration default */
duration: number;
/** Always 0 inside a factory: MOS applies the delay itself */
delay: number;
/** Units for duration and delay ("ms" or "s") */
timeUnits: "ms" | "s";
/** Travel distance for directional animations in px */
distance: number;
/** CSS easing string */
easing: EasingKeyword | string;
/** If true, an element animates only once */
once: boolean;
/** If true, elements animate when scrolling up as well as down (requires once: false) */
mirror: boolean;
/** Disable condition */
disable: DeviceDisable;
/** If true, automatic DOM MutationObserver is not started */
disableMutationObserver: boolean;
/** DOM event that triggers MOS to start. Defaults to "DOMContentLoaded" */
startEvent: string;
/** Throttle delay for scroll events in ms */
throttleDelay: number;
/** Debounce delay for resize/orientation events in ms */
debounceDelay: number;
/** 9-grid intersection that decides when the animation triggers */
anchorPlacement: AnchorPlacement;
/** Class added to every element once MOS has prepared it (false to disable) */
initClassName: string | false;
/** Class added to an element while it is animated in (false to disable) */
animatedClassName: string | false;
/** If true, the value of data-mos is also added as class names while animated in */
useClassNames: boolean;
/** If true, MOS is disabled for users who prefer reduced motion */
respectReducedMotion: boolean;
/** Preset animation name (the value of `data-mos`) */
keyframes: string;
/** Selector of anchor element whose position controls trigger */
anchor?: string;
/** Value of `data-mos-id`, used for the `mos:in:<id>` / `mos:out:<id>` events */
id?: string;
}

motion-on-scroll also exports functions directly:

import { init, refresh, refreshHard, destroy, registerAnimation, registerEasing, registerKeyframes } from 'motion-on-scroll';

They are identical to the namespaced versions.