<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Shrey Saraswat</title>
    <description>The latest articles on DEV Community by Shrey Saraswat (@shreysaraswatweb).</description>
    <link>https://dev.to/shreysaraswatweb</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F835947%2Ff288531e-bbb9-4a65-85fc-67cf9d822a1e.jpeg</url>
      <title>DEV Community: Shrey Saraswat</title>
      <link>https://dev.to/shreysaraswatweb</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shreysaraswatweb"/>
    <language>en</language>
    <item>
      <title>"Frontend Performance in 2026: The Techniques That Actually Move the Needle Now"</title>
      <dc:creator>Shrey Saraswat</dc:creator>
      <pubDate>Tue, 29 Sep 2026 07:44:01 +0000</pubDate>
      <link>https://dev.to/shreysaraswatweb/frontend-performance-in-2026-the-techniques-that-actually-move-the-needle-now-445j</link>
      <guid>https://dev.to/shreysaraswatweb/frontend-performance-in-2026-the-techniques-that-actually-move-the-needle-now-445j</guid>
      <description>&lt;p&gt;Most "frontend performance" checklists still read like it's 2021: split your bundles, compress your images, use a CDN.&lt;/p&gt;

&lt;p&gt;All still true.&lt;/p&gt;

&lt;p&gt;None of it explains why a site can pass Lighthouse and still feel janky the moment someone clicks something.&lt;/p&gt;

&lt;p&gt;That gap exists because the metric that actually measures "does this feel responsive" changed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interaction to Next Paint (INP)&lt;/strong&gt; replaced First Input Delay as an official Core Web Vital back in March 2024, and as of early 2026 it's still the metric most sites fail — reporting puts INP as the most commonly-missed Core Web Vital, with a large share of sites still over the 200ms threshold.&lt;/p&gt;

&lt;p&gt;FID only measured the delay before the browser started processing your &lt;em&gt;first&lt;/em&gt; click.&lt;/p&gt;

&lt;p&gt;INP measures every interaction on the page — clicks, taps, key presses — and reports the worst one.&lt;/p&gt;

&lt;p&gt;You can't game a single data point anymore.&lt;/p&gt;

&lt;p&gt;That shift changes what "performance work" should mean in practice.&lt;/p&gt;

&lt;p&gt;This isn't a rehash of the code-splitting/image-optimization basics — it's what's actually new or newly relevant on top of that foundation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The old checklist still matters, briefly
&lt;/h2&gt;

&lt;p&gt;Skip this section if you've already got these covered.&lt;/p&gt;

&lt;p&gt;If not, do them first — nothing below replaces them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Code splitting&lt;/strong&gt; — &lt;code&gt;React.lazy()&lt;/code&gt; + &lt;code&gt;Suspense&lt;/code&gt;, or Angular's lazy-loaded feature modules. Don't ship the whole app on first load.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Image optimization&lt;/strong&gt; — WebP/AVIF, &lt;code&gt;srcset&lt;/code&gt; for responsive sizing, lazy-load offscreen images.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Render-blocking resources&lt;/strong&gt; — inline critical CSS, &lt;code&gt;defer&lt;/code&gt;/&lt;code&gt;async&lt;/code&gt; non-critical JS, &lt;code&gt;font-display: swap&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Caching + CDN&lt;/strong&gt; — hashed filenames so aggressive caching is safe, serve static assets from an edge, not your origin.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are still correct.&lt;/p&gt;

&lt;p&gt;They're also table stakes — most competent frontend teams already do them.&lt;/p&gt;

&lt;p&gt;What follows is where the actual gains are hiding in 2026.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Diagnose INP with the Long Animation Frames API, not guesswork
&lt;/h2&gt;

&lt;p&gt;The old Long Tasks API told you &lt;em&gt;that&lt;/em&gt; something blocked the main thread for 50ms+.&lt;/p&gt;

&lt;p&gt;It didn't tell you &lt;em&gt;what&lt;/em&gt; — was it a script, a style recalculation, layout?&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Long Animation Frames (LoAF) API&lt;/strong&gt; exposes that breakdown: script attribution, style/layout duration, and which specific function was responsible.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PerformanceObserver&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getEntries&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Blocking duration:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;blockingDuration&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scripts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;invoker&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;long-animation-frame&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;buffered&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you've been trying to fix INP by guessing which component is slow, this replaces the guessing with an actual attribution trail. Chromium supports it; check current browser coverage before you build tooling around it exclusively.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Cut main-thread work with selective hydration
&lt;/h2&gt;

&lt;p&gt;A big source of poor INP in component-heavy apps isn't one slow interaction — it's the sheer amount of JavaScript competing for the main thread before the page ever becomes interactive. &lt;strong&gt;Islands architecture&lt;/strong&gt; (Astro, Qwik, and increasingly meta-frameworks built on React/Vue) addresses this directly: most of the page ships as static HTML, and only the components that actually need interactivity hydrate — and only when they're needed, not all at once on load.&lt;/p&gt;

&lt;p&gt;The practical version of this in a React app you're not rewriting: audit what's actually interactive above the fold. A hero section with a static image and heading doesn't need to hydrate before a click handler three screens down does. If your framework supports partial or deferred hydration, that's real INP budget back.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Tell the browser what actually matters with &lt;code&gt;fetchpriority&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Browsers guess resource priority based on tag type and position. Sometimes the guess is wrong — a below-the-fold image loads before your actual LCP candidate. The &lt;code&gt;fetchpriority&lt;/code&gt; attribute overrides that guess:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/hero.avif"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Product dashboard"&lt;/span&gt; &lt;span class="na"&gt;fetchpriority=&lt;/span&gt;&lt;span class="s"&gt;"high"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/footer-logo.svg"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Partner logo"&lt;/span&gt; &lt;span class="na"&gt;fetchpriority=&lt;/span&gt;&lt;span class="s"&gt;"low"&lt;/span&gt; &lt;span class="na"&gt;loading=&lt;/span&gt;&lt;span class="s"&gt;"lazy"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's a one-line change with a direct effect on LCP when your hero image was competing with less important requests. Check current support on Can I Use before relying on it as your only LCP fix — treat it as a targeted correction, not a substitute for actually optimizing the image itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Stop rendering what nobody can see
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;content-visibility: auto&lt;/code&gt; tells the browser to skip layout and paint work for off-screen content until it's about to become visible, while still reserving space so layout doesn't shift:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.long-list-item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;content-visibility&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;contain-intrinsic-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;200px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* estimated size, prevents CLS */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For long lists, comment sections, or any page with a lot of below-the-fold DOM, this cuts initial rendering cost without touching your component logic. It's a CSS-only performance win, which is rare enough to be worth calling out. Browser support has broadened over the last couple of years — verify current coverage for the browsers your users actually run.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Speculative navigation: prerendering before the click
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Speculation Rules API&lt;/strong&gt; lets the browser prefetch or fully prerender a page &lt;em&gt;before&lt;/em&gt; the user clicks the link, based on rules you define:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"speculationrules"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prerender&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;where&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;href_matches&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/blog/*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eagerness&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;moderate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;}]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On a prerendered navigation, the next page can feel instant — the browser already rendered it in a hidden tab.&lt;/p&gt;

&lt;p&gt;Two honest caveats: it's explicitly a &lt;strong&gt;multi-page-application&lt;/strong&gt; technique (it targets full document navigations, not SPA route changes), and it's still limited availability — Chromium-based browsers only, not Baseline yet.&lt;/p&gt;

&lt;p&gt;If you run a content site, blog, or traditional MPA, it's worth testing. If you're a SPA shipping client-side routing, this doesn't apply to you the way code-splitting does.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Audit your bundle instead of guessing what's heavy
&lt;/h2&gt;

&lt;p&gt;Tree-shaking and dependency audits aren't new, but the habit of actually &lt;em&gt;looking&lt;/em&gt; still gets skipped under deadline pressure. Run a visualizer before you assume you know what's bloating the bundle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx vite-bundle-visualizer

&lt;span class="c"&gt;# or for webpack&lt;/span&gt;
npx webpack-bundle-analyzer stats.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The recurring surprise is always the same shape: one dependency pulled in for a single utility function, sitting at 30–40kb gzipped. You don't know that until you look at the treemap.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trade-offs worth being upfront about
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Technique&lt;/th&gt;
&lt;th&gt;Where it helps&lt;/th&gt;
&lt;th&gt;Where it doesn't&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;LoAF API&lt;/td&gt;
&lt;td&gt;Diagnosing &lt;em&gt;why&lt;/em&gt; INP is bad&lt;/td&gt;
&lt;td&gt;Doesn't fix anything by itself — it's a diagnostic tool&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Selective hydration&lt;/td&gt;
&lt;td&gt;Component-heavy apps with a lot of non-interactive content&lt;/td&gt;
&lt;td&gt;Requires framework support; not a drop-in for existing React SPAs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fetchpriority&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Correcting a wrong LCP-candidate guess&lt;/td&gt;
&lt;td&gt;Doesn't help if the image itself is unoptimized&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;content-visibility&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Long pages with lots of off-screen DOM&lt;/td&gt;
&lt;td&gt;Needs a reasonable &lt;code&gt;contain-intrinsic-size&lt;/code&gt; estimate or you'll get CLS instead&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Speculation Rules&lt;/td&gt;
&lt;td&gt;Multi-page apps, content sites&lt;/td&gt;
&lt;td&gt;Doesn't apply to SPA client-side routing; Chromium-only today&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;None of these replace the fundamentals. They're what's left to optimize once code splitting, image formats, and caching are already handled — which is exactly the point where a lot of teams stop, because the easy wins are gone and the next layer requires knowing these exist.&lt;/p&gt;

&lt;h2&gt;
  
  
  A quick checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Have you measured INP with real user data (CrUX, RUM), not just lab Lighthouse scores?&lt;/li&gt;
&lt;li&gt;Do you know &lt;em&gt;which&lt;/em&gt; interactions are slow, or are you guessing? (LoAF API answers this)&lt;/li&gt;
&lt;li&gt;Is everything above the fold actually necessary to hydrate immediately?&lt;/li&gt;
&lt;li&gt;Does your LCP image have &lt;code&gt;fetchpriority="high"&lt;/code&gt; and skip &lt;code&gt;loading="lazy"&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;Have you looked at a bundle visualizer in the last quarter, or are you assuming you know what's in there?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Worth discussing
&lt;/h2&gt;

&lt;p&gt;If you're on a multi-page site, have you tried the Speculation Rules API yet — and did it actually feel instant, or did prerendering cost outweigh the win?&lt;/p&gt;

&lt;p&gt;And for anyone dealing with INP specifically: &lt;strong&gt;what turned out to be your actual bottleneck once you looked, versus what you assumed it would be?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>frontend</category>
      <category>performance</category>
    </item>
    <item>
      <title>A Practical Guide to React's New &lt;ViewTransition&gt;: What Actually Animates (and What Doesn't)</title>
      <dc:creator>Shrey Saraswat</dc:creator>
      <pubDate>Wed, 23 Sep 2026 11:18:25 +0000</pubDate>
      <link>https://dev.to/shreysaraswatweb/a-practical-guide-to-reacts-new-what-actually-animates-and-what-doesnt-3oh3</link>
      <guid>https://dev.to/shreysaraswatweb/a-practical-guide-to-reacts-new-what-actually-animates-and-what-doesnt-3oh3</guid>
      <description>&lt;p&gt;&lt;strong&gt;React 19.3&lt;/strong&gt; shipped on npm on &lt;strong&gt;September 9, 2026&lt;/strong&gt;, and it quietly stabilized something a lot of us have wanted for years: a native way to animate UI changes without reaching for a third-party library.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What &lt;code&gt;&amp;lt;ViewTransition&amp;gt;&lt;/code&gt; actually is&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;It's a component that wraps part of your UI and tells React: "&lt;em&gt;when this changes, animate it using the browser's native &lt;u&gt;View Transition API &lt;/u&gt; instead of just swapping the DOM.&lt;/em&gt;"&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ViewTransition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;startTransition&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Panel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;showItem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setShowItem&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;
        &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nf"&gt;startTransition&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;setShowItem&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;}}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;showItem&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;➖&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;➕&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;showItem&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ViewTransition&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Details&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ViewTransition&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;)}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Toggle &lt;code&gt;showItem&lt;/code&gt;, and instead of the panel just popping in and out, it cross-fades. No &lt;strong&gt;CSS&lt;/strong&gt; animation library, no manual &lt;code&gt;onExit&lt;/code&gt; juggling.&lt;/p&gt;

&lt;p&gt;React decides which kind of animation to run based on how the tree changed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;enter&lt;/strong&gt; — the &lt;code&gt;&amp;lt;ViewTransition&amp;gt;&lt;/code&gt; gets added&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;exit&lt;/strong&gt; — it gets removed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;update&lt;/strong&gt; — its children change style or content&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;share&lt;/strong&gt; — a named  moves from one place to another&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The rule that trips people up&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Here's the part most quick-recap posts gloss over: &lt;code&gt;&amp;lt;ViewTransition&amp;gt;&lt;/code&gt; &lt;strong&gt;doesn't animate every update&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It only animates changes caused by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;startTransition&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;&amp;lt;Suspense&amp;gt;&lt;/code&gt; reveal&lt;/li&gt;
&lt;li&gt;&lt;code&gt;useDeferredValue&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A plain &lt;code&gt;setState&lt;/code&gt; call inside a regular event handler won't trigger the animation — it just updates immediately, the same as always. This is deliberate. React treats "urgent" interactions &lt;strong&gt;(typing, dragging, anything that needs to feel instant)&lt;/strong&gt; differently from "non-urgent" ones &lt;strong&gt;(navigating, revealing content)&lt;/strong&gt;, and only the latter get animated.&lt;/p&gt;

&lt;p&gt;So if you wrap something in &lt;code&gt;&amp;lt;ViewTransition&amp;gt;&lt;/code&gt; and nothing happens, the first thing to check isn't your CSS — it's whether the state update is actually wrapped in &lt;code&gt;startTransition&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Customizing animations by cause: &lt;code&gt;addTransitionType&lt;/code&gt;&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A single piece of state can change for different reasons that should animate differently. Classic example: a carousel. Clicking "next" should slide left-to-right; clicking "previous" should slide the other way — even though both actions just update the same &lt;code&gt;currentSlide&lt;/code&gt; number.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;addTransitionType&lt;/code&gt; lets you attach a label to the cause of the update:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;nextSlide&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;startTransition&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;addTransitionType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setCurrentSlide&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;previousSlide&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;startTransition&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;addTransitionType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;previous&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setCurrentSlide&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Then map each type to a different animation:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ViewTransition&lt;/span&gt;
  &lt;span class="na"&gt;enter&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;from-right&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;previous&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;from-left&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;to-left&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;previous&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;to-right&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Page&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ViewTransition&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;React also exposes the transition type as a browser &lt;u&gt;view transition type&lt;/u&gt;&lt;/em&gt;, so you can scope the actual animation in plain CSS using &lt;code&gt;:active-view-transition-type(...)&lt;/code&gt; instead of inline objects, if you'd rather keep the animation logic out of your components.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Where it gets genuinely interesting: Suspense&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This is the part that made me actually want to try it. You can wrap a &lt;code&gt;&amp;lt;Suspense&amp;gt;&lt;/code&gt; boundary in &lt;code&gt;&amp;lt;ViewTransition&amp;gt;&lt;/code&gt; and animate the swap from fallback to real content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ViewTransition&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt; &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Loading&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ViewTransition&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can even use it to coordinate image and font loading — wrapping an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; and a &lt;code&gt;@font-face&lt;/code&gt; declaration in &lt;code&gt;&amp;lt;ViewTransition&amp;gt;&amp;lt;Suspense&amp;gt;&lt;/code&gt; means React waits for both to be ready before revealing them together, instead of letting them flicker in independently as they finish.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But the default behavior has a rough edge.&lt;/strong&gt; If you just wrap a Suspense boundary like above, every reveal animates — including ones where the content was already cached and should just appear instantly. That feels like the app got slower, not smoother.&lt;/p&gt;

&lt;p&gt;The fix is to be explicit about what should and shouldn't animate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ViewTransition&lt;/span&gt; &lt;span class="na"&gt;update&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"auto"&lt;/span&gt; &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"none"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt; &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Fallback&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ViewTransition&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives you three rules worth keeping in mind whenever you combine &lt;code&gt;&amp;lt;ViewTransition&amp;gt;&lt;/code&gt; with Suspense:&lt;/p&gt;

&lt;p&gt;Fallbacks should appear &lt;strong&gt;immediately, without animation —&lt;/strong&gt; the loading state shouldn't feel delayed&lt;br&gt;
The swap from fallback to final content &lt;code&gt;should animate —&lt;/code&gt; that's the actual payoff&lt;br&gt;
Content that's already cached and doesn't suspend should appear &lt;strong&gt;immediately, without animation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Skip that last one and you'll animate things that were never actually loading, which just reads as unnecessary lag to the user.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Common mistakes to watch for&lt;/strong&gt;
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mistake&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Forgetting &lt;code&gt;startTransition&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Nothing animates, state just updates instantly&lt;/td&gt;
&lt;td&gt;Wrap the update in &lt;code&gt;startTransition&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Animating every Suspense reveal&lt;/td&gt;
&lt;td&gt;Cached content feels artificially slow&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;update="auto" default="none"&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Using &lt;code&gt;&amp;lt;ViewTransition&amp;gt;&lt;/code&gt; for React Native&lt;/td&gt;
&lt;td&gt;It's DOM-only for now&lt;/td&gt;
&lt;td&gt;Native/other-platform support isn't there yet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Expecting it to replace all animation libraries&lt;/td&gt;
&lt;td&gt;It only animates transition-triggered changes&lt;/td&gt;
&lt;td&gt;Keep a library for hover states, gestures, and non-transition micro-interactions&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Should you adopt it now?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Honestly — probably, for the cases it's built for. It's stable, it requires no build step or extra dependency, and it's built on a real web standard rather than a JS-computed animation loop. If you're currently hand-rolling enter/exit animations with &lt;code&gt;useEffect&lt;/code&gt; and &lt;strong&gt;CSS classes&lt;/strong&gt;, this replaces that machinery directly.&lt;/p&gt;

&lt;p&gt;Where I'd hold off: if you're deep into a library like &lt;strong&gt;Framer Motion&lt;/strong&gt; for complex gesture-driven interactions &lt;strong&gt;(drag, spring physics, layout animations outside of React's transition model)&lt;/strong&gt;, there's no reason to rip that out.&lt;br&gt;
&lt;code&gt;&amp;lt;ViewTransition&amp;gt;&lt;/code&gt; solves a specific, narrower problem — animating mounts, unmounts, and content swaps tied to state transitions — not general-purpose animation.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;A quick checklist&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Is the state update wrapped in &lt;code&gt;startTransition&lt;/code&gt; (or a Suspense reveal / &lt;code&gt;useDeferredValue&lt;/code&gt;)?&lt;/li&gt;
&lt;li&gt;Does this update need different animations depending on cause? → use &lt;code&gt;addTransitionType&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Are you animating a Suspense boundary? → set &lt;code&gt;update="auto" default="none"&lt;/code&gt; to avoid animating cached content&lt;/li&gt;
&lt;li&gt;Do you actually need a full animation library for this interaction, or does &lt;code&gt;&amp;lt;ViewTransition&amp;gt;&lt;/code&gt; cover it?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Worth discussing&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Has anyone here actually shipped &lt;code&gt;&amp;lt;ViewTransition&amp;gt;&lt;/code&gt; in production yet? I'm curious whether the Suspense-fallback behavior needed more tuning than the docs suggest, and whether you kept an existing animation library around alongside it or dropped it entirely.&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>frontend</category>
    </item>
  </channel>
</rss>
