Animated Transitions, No JavaScript Required

There's something about native mobile apps that's hard to copy on the web: things move. Tap a photo and it expands. Go back and it shrinks to where it came from. The browser's View Transition API has been closing that gap, and webforJ 25.11 brings it to Java with webforJ View Transitions.
To see what this looks like in practice, I threw together a quick travel destinations app with a card grid and detail pages to browse through. It shows two things at once: slide animations between routes via @RouteTransition, and a shared element morph where the card thumbnail expands into the full hero image on the detail page.
How it works
Before getting into the Java API, it's worth knowing what the browser is actually doing. When a view transition fires, the browser takes a snapshot of the current page, applies your DOM changes, then animates between the old snapshot and the new live content. The browser handles all of that on its own.
The tricky part for server-side frameworks is timing. DOM mutations happen on the server, not instantly in the browser, so the browser needs a way to know when your changes are done. webforJ handles this by wrapping your component updates in a callback and signaling the browser once the server-side work is complete.
Basic usage
Start with Page.getCurrent().startViewTransition(), which returns a transition builder, ViewTransition. The only method you need to call before start() is onUpdate(), where you make your actual component changes:
Page.getCurrent().startViewTransition()
.onUpdate(done -> {
container.remove(oldView);
container.add(newView);
done.run();
})
.start();
done.run() signals to the browser that your DOM changes are complete; skip it and the transition hangs. Calling start() without an onUpdate callback throws an IllegalStateException.
Without any extra configuration, you get a crossfade. That's already a big improvement over a snap cut, and it only takes a few lines to set up.
Declarative route transitions
For most navigation scenarios, you don't need any of the above. @RouteTransition on a route class is enough; the router handles the animation lifecycle automatically:
@Route
@RouteTransition(enter = ViewTransition.ZOOM, exit = ViewTransition.FADE)
public class DashboardView extends Composite<FlexLayout> {
// view implementation
}
Set enter and exit, and you're done. It accepts ViewTransition constants, or a custom string if you've defined your own CSS. Reach for startViewTransition() directly when you need to animate non-navigation changes, combine enter and exit on different components, or work with shared element morphing.
