Hi friends đź‘‹ This week's newsletter is brought to you by one of those nasty colds that refuse to go away. In fact, I'm pretty sure I had this same cold when I wrote the previous newsletter, and I wouldn't be surprised if I still have it by the next one. So, you know, I guess I have a new co-writer now.
Today we have a special React-takeover edition of Frontend at Scale. Well, it's not really a takeover, but it is a very React-centric issue. Yes, I know React isn't everyone's cup of tea, but I finally got a chance to play with its new View Transitions API over the past few weeks, and I'm just too excited not to tell you about it.
If you're more of a Vanilla JS type of person, I've got you covered as well. We also have a new episode of Frontend.fm with the founder of Frontend Masters, a fantastic talk on DIY sync engines, and a great list of resources with (surprisingly) only two AI-related links in it.
Let's dive in.
MAXI'S RAMBLINGS
Experimenting with React View Transitions
Do you have a favorite browser API? It’s not the IndexedDB API, is it? I hope it’s not, but to each their own I guess.
Mine is the View Transition API, and you’ll know it’s my favorite one because I just won’t stop making demos with it.
I also like React quite a lot, and while using view transitions in React has always been possible, having to work around the mechanics of its rendering loop wasn’t always fun.
So when Next.js 15.2 came out a couple of weeks ago with experimental support for React’s new View Transition component, I immediately dropped everything to give it a try. Thankfully I wasn’t holding my children.
Today, I want to share what I learned about this new unstable (for now) API over the past couple of weeks. So grab your lab coat and safety glasses and follow me into this well-lit room on the right. We’re about to get experimental 🧪
The Shortest Intro to View Transitions
If you’re not familiar with the View Transition API, the best place to learn more about it is the Chrome for Developers website. But if you just want to get the gist of it, here’s a very brief introduction:
The View Transition API is a new feature of the web platform that enables smooth animations between different views or pages of a web application. We can use it to animate any element on the page—text, images, videos—and we can control the transitions via a simple JavaScript API and plain old CSS animations.
While there are many use cases for view transitions, one of the most interesting ones is that we can use them to animate elements across page navigations; whether they’re handled by a client-side router (i.e., in a single-page application) or by the browser, like when we navigate across different documents (i.e., in a multi-page application.)
We can also tag elements on the page with a unique view-transition-name
which will cause the browser to treat them as the same element during a transition. This is how we get those fancy transitions where an element on the page seamlessly resizes and moves across page navigations.

Now, as I mentioned earlier, working with the View Transition API in React components has always been a bit… let’s say, clunky. Since we don’t actually control when the DOM is updated in a React application, implementing view transitions with this framework meant that always had to follow two very important rules:
- Start transitions before setting the state that will cause the transition to happen.
- Wrap the state update in a
flushSync
call to ensure that the DOM has been updated by the time the transition finishes.
Having to follow these rules not only takes away from the simplicity of the native API but, perhaps more importantly, can also have a big performance impact in the case of slow state updates.
This is where React’s new <ViewTransition>
component comes in. And like any great API should, it not only fixes the clunkiness of working with the browser API directly but also comes bearing some additional cool gifts.
Enter React’s View Transitions
Using React’s <ViewTransition> component is as simple as it should be:
It might seem like not much is going on here, but we’re getting a ton of power by simply wrapping our elements in a <ViewTransition>
component. Here are the main benefits we get from working with it:
1. Automatically Starting View Transitions
When we use the <ViewTransition>
component, React kicks off the transitions (by calling the browser’s native startViewTransition()
function) automatically at the right times. This is helpful for a couple of reasons:
- It solves the clunkiness and performance impact we were talking about earlier. By hooking into its internal rendering cycle, React can make the call at the best time possible without us having to worry about using the
flushSync()
escape hatch. - It detaches the “origin” event of the transition from the transition itself. For instance, if the transition starts as part of clicking a button, with React’s API the button doesn’t need to be aware of the fact that there’s some element on the page that will transition. This is great for reducing the coupling between our components.
View transitions in React only trigger for asynchronous updates: useDeferredValue
, startTransition
, Actions and <Suspense>
going from callback to content.
But not every async update will end up triggering a transition. React uses a series of heuristics (described in this PR for now) to determine if and when it should start a transition. This is useful because it avoids calling the startViewTransition function unnecessarily.
2. Just-in-Time View Transition Names
When we wrap an element on the page with the <ViewTransition>
component, React will create a fragment with a view-transition-name
around it so that the element we’re wrapping can animate independently. We can pass a specific name
prop, or React will generate a random name if we don’t provide one.
But here’s the thing: React won’t apply the view transition name right away—instead, it will apply it “just in time” right before the transition starts.
This is a best practice when working with View Transitions because it helps us avoid a couple of common pitfalls: animating elements that we don’t want to animate at a given time, and having too many elements on the page with a transition name, which could hurt performance and cause our transitions to look choppy.
This is a massive helper when working with View Transitions at scale. While manually adding and removing view transition names “just in time” isn’t necessarily hard, having to do it for hundreds of components across an entire application can quickly get out of hand.
3. Lifecycle View Transition Classes
In addition to the name
prop, the ViewTransition
component accepts a className
property and a number of life-cycle props: enter
, exit
, update
, layout
and share
. All of these will be conditionally applied as classes to our View Transitions at the right times.
For instance, if we wanted our elements to have dedicated “enter” and “exit” animations when they enter or leave the page, we could give them dedicated class names and target them with CSS:
For each life-cycle event, the component also supports a callback property (e.g. onEnter
and onExit
), which can be super helpful when we want to execute some logic as part of an element transitioning between different states.
If you want to see some of these features in action, Matt Perry from the Motion team wrote a great interactive article that goes over these in more detail. I also recorded a very improvised video with my initial thoughts on the API after building a few demos with it.
Here's the fanciest of those demos ✨
After playing with this API for the past couple of weeks, React View Transitions get a double thumbs up from me. It certainly isn't perfect yet (I ran into a few cases where transitions didn't run when I expected them to happen), but the API is very simple, and it mostly just works. And more importantly, it fixes pretty much all of the difficulties that working with view transitions in React used to have.
I plan to write a complete guide with everything you can do with React View Transitions as the API gets stable. So if you’re a fellow member of the View Transitions Fan Club, keep an eye out for it on the Frontend at Scale blog.
And if you’re part of the IndexedDB Fan Club… well, I can’t help you with that, but I think they meet in that room over there—just follow the sound of people crying uncontrollably.
​FRONTEND.FM​
Simple Tech Stacks and the Future of Tech Education with Marc Grabanski
​Marc Grabanski joined me on the latest episode of Frontend.fm to chat about his journey in tech, the origin story of Frontend Masters, the impact of AI on tech education, and the value of simple tech stacks.
If you listen to the episode and think "why does Maxi sound like he's sick?" it's because, well, I very much was (it was that nasty cold I told you about in the intro!) Luckily, you aren't here to listen to my ramblings, so don't let my cold distract you from my guest's wonderful insights. I really enjoyed this conversation with Marc, and I'm sure you will as well.
You can listen to the full episode on YouTube, Spotify, and Apple Podcasts. Don't forget to subscribe to the podcast on your favorite platform to be the first to know when a new episode comes out.
​
Add to your queue |
ARCHITECTURE SNACKS
Links Worth Checking Out
- Ben Holmes gave a fantastic talk at JSWORLD last week, during which he live-coded a sync server using Astro and a local SQLite database. Did you know we can ship a SQLite file to the browser and run queries on it, purely client-side? Why did nobody tell me we were allowed to do that? Anyway, this was a great talk, and it’s definitely my “I want to see something cool” pick for the week.
- In line with our View Transitions theme this week, this article by Jim Nielsen on building websites with lots of little HTML pages shows a great example of how we can use this browser API to make a static website look dynamic without shipping a single line of JavaScript.
- Simon Willison wrote about how he uses LLMs to help him write code. It’s an amazing article full of practical advice. If you’ve been searching for ways to get the most out of our new coding companions, definitely give this one a read.
- And if Simon’s advice isn’t enough, Steve Sewell from the Builder.io team shared his best tips on how to use Cursor—but that can probably be applied to any IDE with a coding agent.
- Functions are coming to CSS soon! They’re pretty similar to Sass mixins, except they have return values and don’t require us to install Ruby on our computers for some reason. Juan Rodriguez wrote a nice overview of how they work on CSS Tricks.
- I enjoyed this essay by Mark Griffin on what makes code hard to read, complete with a lesson on the history of complexity metrics and a few useful patterns for improving the readability of our code.
- If you’re feeling like JavaScript Fatigue is striking back, you’re certainly not alone. Allen Pike wrote about his experience coming back to JavaScript frameworks after 10 years of not using the language, sharing what he thinks are the different flavors of “boring” JavaScript stacks we have available these days.
- ​Great software design looks underwhelming—an interesting thought piece by Sean Goedecke on how we can achieve simplicity in software by “designing failure modes out of existence.”
That’s all for today, friends! Thank you for making it all the way to the end. If you enjoyed the newsletter, it would mean the world to me if you’d share it with your friends and coworkers. (And if you didn't enjoy it, why not share it with an enemy?)
Did someone forward this to you? First of all, tell them how awesome they are, and then consider subscribing to the newsletter to get the next issue right in your inbox.
I read and reply to all of your comments. Feel free to reach out on Twitter, LinkedIn, or reply to this email directly with any feedback or questions.
Have a great week đź‘‹
– Maxi