🎎 useViewTransition

A lightweight React 19 hook with Next.js 15 App Router integration for native View Transitions API

React 19Next.js 15TypeScript~100 lines totalZero dependencies

âœĻ Why Use This Instead of npm Packages?

ðŸŠķ

Ultra Lightweight

Only ~20 lines of actual code. No dependencies, no bloat. Perfect when you don't need complex features.

ðŸŽŊ

Simple & Focused

Does one thing well: wraps your state updates with View Transitions API. No complexity, easy to understand.

⚡

No Build Step

Copy-paste directly into your project. No npm install, no version conflicts, no package.json updates.

🔧

Full Control

Own the code. Modify it to fit your exact needs. No waiting for maintainers or dealing with breaking changes.

ðŸ“Ķ

Zero Bundle Impact

Adds virtually no size to your bundle. Existing packages add 5-50KB+ with features you might not need.

🎓

Educational

See exactly how View Transitions integrate with React. Great for learning and understanding the API.

ðŸ’ŧ The Complete Hook

typescript
/**
 * View Transitions API Hook for React 19
 * A production-ready React hook that integrates the native View Transitions API
 * with React 19's concurrent features for smooth, hardware-accelerated UI transitions.
 */

import { startTransition } from "react";
import { flushSync } from "react-dom";

interface ViewTransition {
  finished: Promise<void>;
  ready: Promise<void>;
  updateCallbackDone: Promise<void>;
  skipTransition(): void;
}

declare global {
  interface Document {
    startViewTransition(
      callback: () => void | Promise<void>
    ): ViewTransition;
  }
}

export function useViewTransition() {
  return (updateFn: () => void) => {
    // Check for browser environment and API availability
    if (typeof document !== "undefined" && "startViewTransition" in document) {
      // Native View Transitions API available
      document.startViewTransition(() => {
        flushSync(updateFn);
      });
    } else {
      // Graceful fallback for unsupported browsers
      startTransition(updateFn);
    }
  };
}

📈 Stats

~100
Lines of Code (total)
0
Dependencies
~2KB
Bundle Size (gzipped)
100%
TypeScript