Skip to main content

View Transitions

Open in ChatGPT
Java API
25.11 Experimental

View transitions provide animated transitions when the DOM changes, reducing visual jarring and maintaining spatial context during navigation or content updates. webforJ integrates with the browser's View Transition API to handle the complexity of coordinating animations between old and new states.

Show Code

Experimental API

This API is marked as experimental since 25.11 and may change in future releases. The API signature, behavior, and performance characteristics are subject to modification.

Basic usage

To create a view transition, use Page.getCurrent().startViewTransition(), which returns a builder for configuring the transition:

Page.getCurrent().startViewTransition()
.onUpdate(done -> {
container.remove(oldView);
container.add(newView);
done.run();
})
.start();

The transition process captures a snapshot of the current state, applies your DOM changes in the onUpdate callback, then animates from the old snapshot to the new content. You must call done.run() to signal when your changes are complete.

The onUpdate callback is required

Calling start() without setting an update callback throws an IllegalStateException.

Applying transitions

webforJ provides predefined transition types that you can apply to components entering or exiting the DOM:

ConstantEffect
ViewTransition.NONENo animation
ViewTransition.FADECrossfade between old and new content
ViewTransition.SLIDE_LEFTContent flows left (like forward navigation)
ViewTransition.SLIDE_RIGHTContent flows right (like back navigation)
ViewTransition.SLIDE_UPContent flows upward
ViewTransition.SLIDE_DOWNContent flows downward
ViewTransition.ZOOMOld content shrinks away, new content grows in
ViewTransition.ZOOM_OUTOld content grows away, new content shrinks in

Use enter() to animate a component being added and exit() to animate a component being removed:

// Animate a component entering the DOM
Page.getCurrent().startViewTransition()
.enter(chatPanel, ViewTransition.ZOOM)
.onUpdate(done -> {
container.add(chatPanel);
done.run();
})
.start();

// Animate a component exiting the DOM
Page.getCurrent().startViewTransition()
.exit(chatPanel, ViewTransition.FADE)
.onUpdate(done -> {
container.remove(chatPanel);
done.run();
})
.start();

Shared component transitions

Shared component transitions create a morphing effect where a component appears to transform from its position in the old view to its position in the new view. This is achieved by giving components the same transition name using the setViewTransitionName() method, available on any component that implements the HasStyle interface.

// In the card view
image.setViewTransitionName("blog-image");

// In the detail view - same name creates the morph
image.setViewTransitionName("blog-image");

When transitioning between these views, the browser animates the component between positions, creating a connected visual experience.

Use unique names

When working with lists or repeated components, include a unique identifier in the transition name. Each component requires its own distinct name to morph correctly to its corresponding component in the new view. Using the same name for multiple visible components causes undefined behavior.

Show Code

List reordering

A common use case for shared component transitions is animating list items when their order changes. By assigning a unique view-transition-name to each item, the browser automatically animates components to their new positions:

// Each card gets a unique transition name based on its ID
card.setViewTransitionName("card-" + item.id());

// When shuffling, just update the DOM - the browser handles animation
Page.getCurrent().startViewTransition()
.onUpdate(done -> {
renderList();
done.run();
})
.start();
Show Code

Custom CSS animations

For full control over animations, you can define custom CSS keyframes. webforJ appends -enter or -exit suffixes to your transition names, which you use to target the view transition pseudo-elements:

/* Define keyframes for entering components */
@keyframes flip-enter {
from {
opacity: 0;
transform: perspective(1000px) rotateX(-90deg);
}
to {
opacity: 1;
transform: perspective(1000px) rotateX(0deg);
}
}

/* Apply to the view transition pseudo-element */
::view-transition-new(flip-in-enter) {
animation: flip-enter 450ms cubic-bezier(0.34, 1.56, 0.64, 1);
transform-origin: top center;
}

::view-transition-old(flip-in-enter) {
display: none;
}

Reference your custom animation by passing its name (without the suffix) to enter() or exit():

// Use "flip-in" - webforJ adds "-enter" suffix automatically
Page.getCurrent().startViewTransition()
.enter(notification, "flip-in")
.onUpdate(done -> {
stage.add(notification);
done.run();
})
.start();

// Use "blur-out" for exit - webforJ adds "-exit" suffix
Page.getCurrent().startViewTransition()
.exit(notification, "blur-out")
.onUpdate(done -> {
stage.remove(notification);
done.run();
})
.start();
Show Code

CSS customization

Each predefined transition type exposes CSS custom properties for fine-tuning:

VariableDefaultDescription
--vt-fade-duration200msAnimation duration
--vt-fade-easingcubic-bezier(0.4, 0, 0.2, 1)Easing function
VariableDefaultDescription
--vt-slide-left-duration200msAnimation duration
--vt-slide-left-easingcubic-bezier(0.4, 0, 0.2, 1)Easing function
--vt-slide-left-distance30%Slide distance
VariableDefaultDescription
--vt-slide-right-duration200msAnimation duration
--vt-slide-right-easingcubic-bezier(0.4, 0, 0.2, 1)Easing function
--vt-slide-right-distance30%Slide distance
VariableDefaultDescription
--vt-slide-up-duration200msAnimation duration
--vt-slide-up-easingcubic-bezier(0.4, 0, 0.2, 1)Easing function
--vt-slide-up-distance30%Slide distance
VariableDefaultDescription
--vt-slide-down-duration200msAnimation duration
--vt-slide-down-easingcubic-bezier(0.4, 0, 0.2, 1)Easing function
--vt-slide-down-distance30%Slide distance
VariableDefaultDescription
--vt-zoom-duration200msAnimation duration
--vt-zoom-easingcubic-bezier(0.4, 0, 0.2, 1)Easing function
--vt-zoom-scale0.8Scale factor (old zooms out to this, new zooms in from this)
VariableDefaultDescription
--vt-zoom-out-duration200msAnimation duration
--vt-zoom-out-easingcubic-bezier(0.4, 0, 0.2, 1)Easing function
--vt-zoom-out-scale1.2Scale factor (old zooms in to this, new zooms out from this)

To customize, override these variables in your CSS:

:root {
--vt-fade-duration: 300ms;
--vt-slide-left-distance: 50%;
}

For advanced customization, target the view transition pseudo-elements directly:

::view-transition-old(vt-slide-left-exit) {
animation-duration: 400ms;
}

::view-transition-new(vt-slide-left-enter) {
animation-timing-function: ease-out;
}