Native rendering and state

Animate state with view transitions

Wrap a synchronous DOM update in startViewTransition() while preserving the same update and reduced-motion behavior as fallbacks.

Completing, filtering, or reordering tasks can be hard to follow when the board changes instantly. The View Transition API can animate between the old and new rendered states without moving your state logic into an animation library.

Keep the DOM update as a normal function. If document.startViewTransition exists and the user has not requested reduced motion, pass that function to it. Otherwise call the same function directly. Enhancement changes presentation, never whether completion works.

const reduceMotion = matchMedia("(prefers-reduced-motion: reduce)")
function update() { setTaskComplete(card, complete) }

if (document.startViewTransition && !reduceMotion.matches) {
  document.startViewTransition(update)
} else {
  update()
}

The update callback should perform the state change that produces the new view. Do not call the update first and then start a transition; the browser would capture two identical states and have nothing meaningful to animate.

Give stable items unique view-transition-name values only when you need element-level continuity, and ensure names are unique in the rendered view. For a simple first version, the root cross-fade may already make the state change easier to follow.

Reduced motion is not merely “shorter motion.” Prefer the direct update when the user requests reduction. Also test interruptions: a user may trigger another change before an animation finishes, so the data operation must remain correct independently of transition timing.

Filter the board with and without the API branch, then enable reduced motion in your operating system. The same tasks must appear in every case. Slow animations in DevTools and activate another filter midway through to expose timing assumptions. The final task set should follow the latest selected filter, regardless of visual interruption. If the update happens twice, check that you call update() only inside the supported branch or the fallback, never both.

Lesson completed

Take this course offline

Get every free book, course edition, and software download.

Get the download library →