animate

animate can animate a DOM element or multiple elements to a set of CSS styles:

import { animate } from "motion"

// Animate via selector
animate(".box", { x: 100 }, { duration: 1 })

// Animate element or array of elements
const boxes = document.querySelectorAll(".box")
animate(boxes, { opacity: 0 }, { easing: "ease-out" })

It can also accept a function, which outputs a progress value between 0 and 1, which you can use to animate anything:

import { animate } from "motion"

animate(
  (progress) => {
    box.innerHTML = progress
  },
  { duration: 0.5 }
)

Keyframes

Single keyframe

By passing a single keyframe, the element will animate from its current style to those defined in the keyframe:

animate(element, {
  opacity: 1,
  transform: "rotate(360deg)",
})

Multiple keyframes

By defining a value as an array, it'll animate through each keyframe in turn:

animate(element, {
  transform: ["rotate(90deg)", "translateX(100px) rotate(45deg)", "none"],
})

Wildcards

null is a special wildcard. As the first keyframe, it'll be replaced by the current value as read from the DOM.

element.style.opacity = "0.5"

animate(element, {
  opacity: [
    null, // 0.5
    0.8,
    1,
  ],
})

Subsequent null values will be replaced by the previous keyframe. Useful for keeping a style static for some of the animation. This way, you only have to change it in one place if you want to tweak the animation.

animate(element, {
  x: [
    0,
    100,
    null, // 100
    200,
  ],
})

Custom keyframe timing

By default, each of these keyframes will be spaced evenly throughout the animation. It's also possible to specify a list of offsets, values between 0 and 1, that defines a relative point in the animation a specific keyframe should be hit:

animate(
  element,
  {
    transform: ["rotate(90deg)", "translateX(100px) rotate(45deg)", "none"],
  },
  { offset: [0, 0.25, 1] }
)

If there are fewer keyframes than offsets defined in offset, the other keyframes will be spaced evenly:

animate(
  element,
  { color: ["red", "yellow", "green", "blue"] },
  { offset: [0, 0.2] } // [...0.6, 1]
)

Custom keyframe easing

By default, easing will apply to the progress of whole animation. It's also possible to define easing between specific keyframes by defining an easing option as any array:

animate(
  element,
  { color: ["red", "yellow", "green", "blue"] },
  { easing: ["ease-in", "linear", "ease-out"] }
)

Options

Options can be defined either for all values:

animate(
  element,
  { opacity: 0, color: ["red", "yellow", "green", "blue"] },
  { duration: 2 }
)

Or overridden for individual values:

animate(
  element,
  { opacity: 0, color: ["red", "yellow", "green", "blue"] },
  {
    duration: 2,
    ease: "linear",
    opacity: { duration: 0.4 },
  }
)

duration

Default: 0.3

A duration, in seconds, that the animation will take to complete.

animate(element, { backgroundColor: "red" }, { duration: 2 })

delay

Default: 0

A duration, in seconds, that the animation will be delayed before starting.

animate(element, { backgroundColor: "red" }, { delay: 0.5 })

When animating multiple elements, the stagger function can be used to offset the delay by increasing amounts across each element:

import { animate, stagger } from "motion"

animate(element, { backgroundColor: "red" }, { delay: stagger(0.1) })

endDelay

Default: 0

A duration, in seconds, that the animation will wait at the end before ending.

animate(element, { backgroundColor: "red" }, { endDelay: 0.5, repeat: 2 })

easing

Default: "ease"

An easing to use for the whole animation, or list of easings to use between individual keyframes.

Accepted easing options are:

  • Basic easings: "linear", "ease", "ease-in", "ease-out", "ease-in-out"
  • Cubic bezier curve: e.g. [.17,.67,.83,.67]
  • Stepped easing: e.g. "steps(2, start)"
  • Custom easing: A JavaScript easing function, for example this bounce easing function.

Provide a single easing to ease the animation as a whole:

animate(element, { transform: "rotate(90deg)" }, { easing: "steps(2, start)" })

Or an array to specifically ease between individual keyframes:

animate(element, { scale: [0, 1, 2] }, { easing: ["ease-in", "ease-out"] })

Note on custom easing: Custom easing support for WAAPI animations is based on the new linear() easing spec.

If a browser doesn't yet support linear() and the value being animated is not an independent transform (x, scale etc), Motion One will fallback to "ease".

direction

Default: "normal"

The direction of animation playback. "normal", "reverse", "alternate", or "alternate-reverse".

animate(element, { transform: "rotate(90deg)" }, { direction: "reverse" })

repeat

Default: 0

The number of times the animation should repeat. Set to Infinity to repeat indefinitely.

animate(element, { transform: "rotate(90deg)" }, { repeat: Infinity })

allowWebkitAcceleration

Default: false

Because of numerous timing bugs in Webkit's accelerated animations, these are disabled by default in Webkit-powered browsers.

However, if the your animation is being disrupted by heavy processing, you can allow acceleration with this setting. It's advised you test these animations thoroughly in both Safari and iOS Chrome.

animate(element, { transform: "scale(2)" }, { allowWebkitAcceleration: true })

If and when Webkit's implementation improves, this option will default to true.

autoplay

Default: true

Whether the animation should start automatically.

animate(element, { transform: "scale(2)" }, { autoplay: false })

Returns

animate returns animation controls