Skip to main content

Motion

MD3 easing and duration tokens — the same curves the components move on.
import { motion } from "@brijbyte/md3-react/tokens";
@import "@brijbyte/md3-react/tokens.css";

MD3 motion is two decisions: an easing curve (how the speed changes) and a duration (how long it runs). The library ships both as tokens, so your app moves on the exact curves the components do — no magic numbers. The same values are available three ways: as CSS variables (--md-sys-motion-*), as a typed JS map (import { motion } from "@brijbyte/md3-react/tokens"), and as Tailwind utilities (ease-emphasized, duration-medium4).

Easing

Easing sets the personality of a transition. Emphasized is the default for most motion — a slow-in, fast-middle, slow-out curve that feels expressive. Standard is its calmer counterpart for small, utility-focused changes. Each set has accelerate and decelerate variants for one-directional motion: elements entering the screen decelerate (fast → slow, settling into place), elements leaving accelerate (slow → fast, exiting decisively). fast-spatial is a springy curve for quick spatial moves.

Emphasized
Emphasized decelerate
Emphasized accelerate
Standard
Standard decelerate
Standard accelerate
Fast spatial
TokenUse for
easing-emphasizedMost transitions that begin and end on screen
easing-emphasized-decelerateElements entering the screen
easing-emphasized-accelerateElements leaving the screen
easing-standardSmall, functional changes (color, state layer)
easing-standard-decelerateSmall enters
easing-standard-accelerateSmall exits
easing-fast-spatialQuick, springy spatial moves

Duration

Duration scales with the size of the change: small elements over short spans, large or complex transitions over longer ones. The scale runs short1short4 (50–200ms), medium1medium4 (250–400ms), and long1long4 (450–600ms). Reach for short for icon and selection changes, medium for most component transitions, and long for large surfaces entering the screen.

short2 · 100ms
short4 · 200ms
medium2 · 300ms
medium4 · 400ms
long2 · 500ms
long4 · 600ms

Using the tokens

Reference the CSS variables directly in any stylesheet — pair an easing with a duration on the property you're animating:

.card {
  transition:
    box-shadow var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard),
    transform var(--md-sys-motion-duration-medium4) var(--md-sys-motion-easing-emphasized);
}

In JS, the typed motion map gives the same values as var(...) references (camelCase keys), handy for inline styles or animation libraries:

import { motion } from "@brijbyte/md3-react/tokens";

<div
  style={{
    transitionTimingFunction: motion.easingEmphasized,
    transitionDuration: motion.durationMedium4,
  }}
/>;

And in a Tailwind v4 project that imports tailwind-tokens.css, every token is a utility — ease-* for the curves and duration-* for the times:

<div className="transition-transform duration-medium4 ease-emphasized" />

Recipe: rotate-through icon swap

The theme toggle and copy button in this site's chrome swap one icon for another by rotating through — the outgoing icon rotates and scales out while the incoming one rotates in, on the emphasized curve. It's just two icons sharing one grid cell (so there's no layout shift) plus a transition; drop this into any project:

<span class="icon-swap" data-swapped>
  <YourFirstIcon class="icon1" />
  <YourSecondIcon class="icon2" />
</span>
.icon-swap {
  display: inline-grid;
  place-items: center;
}
.icon1,
.icon2 {
  grid-area: 1 / 1; /* stack both icons in the same cell */
  transition:
    transform var(--md-sys-motion-duration-medium4) var(--md-sys-motion-easing-emphasized),
    opacity var(--md-sys-motion-duration-medium2) var(--md-sys-motion-easing-standard);
}
/* Second icon waits rotated out; toggle [data-swapped] to cross them over. */
.icon2 {
  transform: rotate(-90deg) scale(0);
  opacity: 0;
}
.icon-swap[data-swapped] .icon1 {
  transform: rotate(90deg) scale(0);
  opacity: 0;
}
.icon-swap[data-swapped] .icon2 {
  transform: none;
  opacity: 1;
}

Reduced motion

All of the above are transitions and animations, so honor the user's system preference — wrap decorative motion in a prefers-reduced-motion guard and let the end state apply instantly:

@media (prefers-reduced-motion: reduce) {
  .icon1,
  .icon2 {
    transition: none;
  }
}