safeViewTransition

Use the awesome, experimental View Transitions API safely, without needing to worry about whether it's available, or whether the user prefers reduced motion.

Allergic to copy-pasting code, or just want to make your node_modules more massive? Install this via npm here.

typescriptjavascript
// This block of code stops of the transition from happening if the user
// doesn't want it
const motionSafeMediaQuery = window.matchMedia(
  '(prefers-reduced-motion: no-preference)'
)
let motionSafe = motionSafeMediaQuery.matches
motionSafeMediaQuery.onchange = () => {
  motionSafe = motionSafeMediaQuery.matches
}
 
export type ViewTransitionCallback = () => void | Promise<void>
 
type ObjectWithStartViewTransition = {
  startViewTransition: (callback: ViewTransitionCallback) => void
}
 
export function safeViewTransition(callback: ViewTransitionCallback) {
  if (
    motionSafe &&
    typeof document !== 'undefined' &&
    'startViewTransition' in document
  ) {
    // Needed until TypeScript catches up
    const doc = document as unknown as ObjectWithStartViewTransition
    doc.startViewTransition(callback)
  } else {
    callback()
  }
}
// This block of code stops of the transition from happening if the user
// doesn't want it
const motionSafeMediaQuery = window.matchMedia(
  '(prefers-reduced-motion: no-preference)'
)
let motionSafe = motionSafeMediaQuery.matches
motionSafeMediaQuery.onchange = () => {
  motionSafe = motionSafeMediaQuery.matches
}
 
export function safeViewTransition(callback) {
  if (
    motionSafe &&
    typeof document !== 'undefined' &&
    'startViewTransition' in document
  ) {
    // Needed until TypeScript catches up
    const doc = document
    doc.startViewTransition(callback)
  } else {
    callback()
  }
}

Usage

typescriptjavascript
safeViewTransition(() => {
  // update the DOM in here, and watch the magic happen!
})
safeViewTransition(() => {
  // update the DOM in here, and watch the magic happen!
})

Demo

Try these demoes in browsers that support the View Transitions API (e.g. Chromium based browsers, including Chrome, Brave, Arc) and ones that don't (e.g. Safari, Firefox) to see these demos gracefully handle when the API is unavailable. You can also try emulating the (prefers-reduced-motion: reduce) media query (in Chrome, open the devtools, hit cmd/ctrl + shift + p, search for prefers-reduced-motion).

Vanilla JS

Vue 3

Created 11/07/23Updated 13/09/23
Found a mistake, or want to suggest an improvement? Source on GitHub here
and see edit history here