React 19.2: ViewTransition and Fragment ref

React 19.2: ViewTransition and Fragment ref

Smooth UI transitions and imperative composition in Canary

At React Conf 2025, the team announced the availability in Canary of two highly anticipated features: ViewTransition and Fragment ref. These APIs aim to smooth interface transitions and better compose imperative behaviors while remaining idiomatic with React. This complete guide details their operation, use cases and best practices for modern React applications.

What Does React 19.2 Bring?

React 19.2 marks an important step in the framework's evolution with two major features:

  • ViewTransition API: automatically animates state changes with smooth transitions, including Shared Element Transitions
  • Fragment ref: exposes an imperative API to manipulate child nodes of a Fragment, enabling composable primitives
  • Performance improvements: reconciler and scheduler optimizations for smoother transitions
  • Better developer experience: improved error messages and enriched DevTools

ViewTransition: Smooth Transitions Between States

The ViewTransition API animates elements that change inside a React Transition, including Shared Element Transitions. This feature draws inspiration from the browser's View Transitions API while integrating perfectly into React's declarative model.

How Does ViewTransition Work?

ViewTransition automatically captures the visual state before and after a change, then creates a smooth animation between both states. Here's a basic example:

import { startTransition, useViewTransition } from 'react';

function ProductList() {
  const [selectedId, setSelectedId] = useState(null);
  const viewTransition = useViewTransition();

  const handleSelect = (id) => {
    startTransition(() => {
      viewTransition.run(() => {
        setSelectedId(id);
      });
    });
  };

  return (
    <div className="grid">
      {products.map(product => (
        <ProductCard
          key={product.id}
          product={product}
          isSelected={selectedId === product.id}
          onClick={() => handleSelect(product.id)}
          style={{ viewTransitionName: `product-${product.id}` }}
        />
      ))}
    </div>
  );
}

Shared Element Transitions

Shared Element Transitions animate an element moving from one position to another, changing size or transforming. This is particularly useful for:

  • List → detail navigation: product image moves and enlarges
  • Image galleries: smooth zoom on a photo
  • Grid reorganization: elements move naturally
  • Modal and overlay: expansion from a button
// List page
<img 
  src={product.image} 
  style={{ viewTransitionName: 'hero-image' }}
  alt={product.name}
/>

// Detail page (same viewTransitionName)
<img 
  src={product.image} 
  style={{ viewTransitionName: 'hero-image' }}
  alt={product.name}
  className="full-width"
/>

Concrete Use Cases

Use CaseUX BenefitComplexity
Page → page navigationVisual continuity, spatial orientationLow
Sort/filter changesPerformance perception, cognitive reductionLow
List transitionsVisual tracking of elements, clarityMedium
Modal and overlayPreserved context, fluidityMedium
Image galleryImmersion, engagementHigh

Configuration and Customization

You can customize transitions with CSS:

::view-transition-old(hero-image),
::view-transition-new(hero-image) {
  animation-duration: 0.3s;
  animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}

::view-transition-old(hero-image) {
  animation-name: fade-out, scale-down;
}

::view-transition-new(hero-image) {
  animation-name: fade-in, scale-up;
}

Current Limitations

  • Availability: Canary only, API subject to change
  • Platform support: DOM only (React Native under study)
  • Browser support: Chrome 111+, Edge 111+, Safari Technology Preview (full support coming)
  • Performance: watch out for complex transitions on large grids (>100 elements)
  • Accessibility: respect prefers-reduced-motion

Fragment ref: Compose Imperative Behaviors

<Fragment ref={...}> exposes an imperative API to manipulate child nodes of a Fragment. This feature solves a long-standing problem: how to apply imperative logic (focus, measurement, animation) to a group of elements without superfluous DOM wrapper?

Why Fragment ref?

Before Fragment ref, to access multiple DOM nodes, you had to:

  • Create an unnecessary <div> wrapper (DOM pollution, CSS impact)
  • Use a refs array (verbose, hard to maintain)
  • Go through portals (complex, lost context)

Example: Focus Management

import { Fragment, useRef, useEffect } from 'react';

function FormSection({ children, autoFocus }) {
  const fragmentRef = useRef(null);

  useEffect(() => {
    if (autoFocus && fragmentRef.current) {
      // Access child nodes of Fragment
      const nodes = fragmentRef.current.getChildNodes();
      const firstInput = nodes.find(node => 
        node.tagName === 'INPUT' || node.tagName === 'TEXTAREA'
      );
      firstInput?.focus();
    }
  }, [autoFocus]);

  return (
    <Fragment ref={fragmentRef}>
      {children}
    </Fragment>
  );
}

Example: Measurement and Layout

function MeasuredList({ items }) {
  const fragmentRef = useRef(null);
  const [totalHeight, setTotalHeight] = useState(0);

  useLayoutEffect(() => {
    if (fragmentRef.current) {
      const nodes = fragmentRef.current.getChildNodes();
      const height = nodes.reduce((sum, node) => 
        sum + node.getBoundingClientRect().height, 0
      );
      setTotalHeight(height);
    }
  }, [items]);

  return (
    <>
      <p>Total height: {totalHeight}px</p>
      <Fragment ref={fragmentRef}>
        {items.map(item => (
          <ListItem key={item.id} {...item} />
        ))}
      </Fragment>
    </>
  );
}

Use Cases

  • Focus management: focus the first input in a group
  • Measurement: calculate total dimensions of multiple elements
  • Animation orchestration: sequence animations on multiple elements
  • Accessibility: announce group changes to screen readers
  • Scroll management: scroll to a group of elements

Limitations

  • Canary only: experimental API, may change
  • Performance: accessing child nodes has a cost, use sparingly
  • Reactivity: child nodes don't update automatically, requires manual tracking

Progressive Adoption

Installing React Canary

npm install react@canary react-dom@canary
# or
yarn add react@canary react-dom@canary

Testing Strategy

  • Start with non-critical pages: test on secondary pages first
  • Measure impact: track UX metrics (engagement, bounce rate)
  • Respect accessibility: test with screen readers and reduced motion
  • Monitor performance: check frame drops and CPU usage

Best Practices

  • Use ViewTransition for state changes, not for purely decorative animations (use CSS instead)
  • Keep transitions short: 200-400ms for most cases
  • Respect prefers-reduced-motion: disable or simplify transitions
  • Test on different devices: performance varies greatly
  • Use Fragment ref sparingly: imperative APIs should be the exception

Conclusion

React 19.2 brings two powerful APIs that enhance the user experience while maintaining React's declarative philosophy. ViewTransition makes interfaces more fluid and intuitive, while Fragment ref unlocks new composition possibilities. While still in Canary, these features are already production-ready for early adopters willing to test them.

Need React UI Expertise?

Our VOID team can help you integrate ViewTransition and enhance your UX. We work on:

  • UI/UX design with smooth transitions
  • React implementation of modern features
  • Performance optimization and accessibility
  • Progressive enhancement strategies
Contact a React expert

Additional Resources

Article published on October 10, 2025. Complete guide to React 19.2 ViewTransition and Fragment ref for React developers.

🌱Eco-designed site