CSS ::view-transition-new() Pseudo-Element
The ::view-transition-new() pseudo-element represents the new visual state of an element during a View Transition. It allows developers to customize how the updated content appears, including fade-in effects, scaling, movement, and other animations between the old and new document states.
Syntax
::view-transition-new(name) {
property: value;
}
The name argument identifies the View Transition group whose new visual state should be styled.
For example:
::view-transition-new(root) {
animation-duration: 500ms;
}
This changes the animation duration of the new visual state for the root transition.
To target a custom element:
::view-transition-new(featured-card) {
animation-duration: 400ms;
}
This targets the new visual state of the group named featured-card.
To target all new transition representations:
::view-transition-new(*) {
animation-duration: 300ms;
}
The universal selector * matches all generated new-state pseudo-elements.
The parentheses are required because ::view-transition-new() is a functional pseudo-element.
How It Works
When a View Transition begins, the browser prepares visual representations of the document before and after an update.
The old state is represented by ::view-transition-old(), while the new state is represented by ::view-transition-new().
The new representation is a live rendering of the updated state rather than a static image captured before the update.
The process generally follows these steps:
- A View Transition starts through JavaScript or an eligible navigation.
- The browser captures the old visual state of participating elements.
- The document changes to its new state.
- The browser prepares the new visual representation.
- The browser generates the transition pseudo-element tree.
- The new representation animates into view while the old representation animates out.
- The temporary pseudo-elements are removed when the transition finishes.
By default, the browser commonly uses a cross-fade animation between the old and new visual states.
Developers can replace or customize that animation using CSS.
The ::view-transition-new() pseudo-element only exists during an active View Transition.
View Transition Pseudo-Element Tree
The browser generates a hierarchy of pseudo-elements to display a View Transition.
A simplified structure looks like this:
::view-transition
::view-transition-group(root)
::view-transition-image-pair(root)
::view-transition-old(root)
::view-transition-new(root)
Each pseudo-element serves a different purpose.
| Pseudo-Element | Purpose |
|---|---|
::view-transition |
Contains all generated transition groups. |
::view-transition-group() |
Controls the position and dimensions of a transition group. |
::view-transition-image-pair() |
Contains the old and new visual representations. |
::view-transition-old() |
Represents the old visual state. |
::view-transition-new() |
Represents the new visual state. |
The ::view-transition-new() pseudo-element is a child of its corresponding ::view-transition-image-pair().
It does not contain child pseudo-elements.
Each transition group can have a new representation, an old representation, or both, depending on which states exist.
Understanding the New Visual State
The ::view-transition-new() pseudo-element represents the updated visual state of a participating element.
For example, consider a card that changes its background color:
.card {
background-color: #0066cc;
}
.card.updated {
background-color: #333;
}
When the class changes during a View Transition, the browser can animate between the blue and dark backgrounds.
The old representation displays the original blue card.
The new representation displays the updated dark card.
The browser can blend these representations to create a smooth visual transition.
The new representation behaves as replaced content, similar to an image.
This means properties such as object-fit and object-position can affect how it is displayed within its generated box.
Unlike the static old snapshot, the new representation reflects the updated visual state during the transition.
The pseudo-element is removed after the transition completes, leaving the updated document visible normally.
Targeting Named Transitions
The view-transition-name property allows individual elements to participate in their own transition groups.
For example:
.featured-card {
view-transition-name: featured-card;
}
The new representation of this group can be styled using:
::view-transition-new(featured-card) {
animation-duration: 500ms;
}
Different elements can have different transition names:
.site-logo {
view-transition-name: site-logo;
}
.featured-card {
view-transition-name: featured-card;
}
Their new visual states can be animated independently:
::view-transition-new(site-logo) {
animation-duration: 250ms;
}
::view-transition-new(featured-card) {
animation-duration: 600ms;
}
The logo uses a shorter animation, while the card uses a longer one.
Each rendered participating element must have a unique transition name within a document state.
The browser normally uses root as the default transition name for the document's root element.
Use ::view-transition-new(root) when styling the incoming root representation.
Creating a Fade-In Animation
A fade-in animation gradually reveals the new visual state.
The following example defines a custom fade-in animation:
@keyframes fade-in-new {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
::view-transition-new(root) {
animation: 500ms ease-out both fade-in-new;
}
The new root representation begins transparent and gradually becomes fully visible.
The animation shorthand specifies the duration, timing function, fill mode, and animation name.
To customize the old state as well:
@keyframes fade-out-old {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
::view-transition-old(root) {
animation: 500ms ease-in both fade-out-old;
}
When combined, the old state fades out while the new state fades in.
This replaces the default animation behavior for the selected old and new representations.
For most simple transitions, the browser's default cross-fade is sufficient.
Creating a Scale Animation
The new visual state can also be animated using CSS transforms.
For example:
@keyframes scale-in-new {
from {
opacity: 0;
transform: scale(0.85);
}
to {
opacity: 1;
transform: scale(1);
}
}
::view-transition-new(featured-card) {
animation: 500ms ease-out both scale-in-new;
}
The new card representation starts slightly smaller and transparent.
It grows to its normal size while becoming fully visible.
This type of animation can be useful when introducing a new card, panel, or other visual component.
The browser may also generate transforms for the surrounding transition group to handle changes in position or dimensions.
Custom transforms should be tested carefully when combined with automatic group movement.
For accessibility, avoid large or unnecessary scaling effects and provide a reduced-motion alternative.
Example
The following example demonstrates a custom fade-in animation applied to the new visual state of a card.
Click the button to change the card's appearance.
HTML:
<div class="vt-new-demo" id="vt-new-demo">
<div class="vt-new-card">
<strong>New Visual State</strong>
<p>Watch the updated card fade into view.</p>
</div>
<button type="button" id="vt-new-toggle">Change Appearance</button>
</div>
CSS:
.vt-new-demo {
max-width: 300px;
}
.vt-new-card {
padding: 20px;
border-radius: 6px;
background-color: #0066cc;
color: #fff;
view-transition-name: vt-new-card;
}
.vt-new-card p {
margin: 8px 0 0;
color: inherit;
}
.vt-new-demo.is-alternate .vt-new-card {
border-radius: 20px;
background-color: #333;
}
.vt-new-demo button {
margin-top: 12px;
padding: 8px 14px;
border: 0;
background-color: #0066cc;
color: #fff;
cursor: pointer;
}
@keyframes vt-new-fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
::view-transition-old(vt-new-card) {
animation: 600ms ease-in both vt-new-fade-out;
}
::view-transition-new(vt-new-card) {
animation: 600ms ease-out both vt-new-fade-in;
}
@keyframes vt-new-fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
JavaScript:
const demo = document.querySelector("#vt-new-demo");
const button = document.querySelector("#vt-new-toggle");
button.addEventListener("click", () => {
const update = () => demo.classList.toggle("is-alternate");
const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (document.startViewTransition && !reduceMotion) {
document.startViewTransition(update);
} else {
update();
}
});
Watch the updated card fade into view.
Try it: Click Change Appearance to switch between the blue and dark card styles.
In supporting browsers, the old card fades out while the new card fades in.
The ::view-transition-new(vt-new-card) rule controls the incoming animation.
The ::view-transition-old(vt-new-card) rule controls the outgoing animation.
Both animations last 600 milliseconds.
If View Transitions are unsupported or reduced motion is preferred, the card changes immediately.
Note: The example uses a unique transition name so the card can animate independently of the rest of the page.
::view-transition-old() vs. ::view-transition-new()
The ::view-transition-old() and ::view-transition-new() pseudo-elements represent opposite sides of the same visual transition.
| Feature | ::view-transition-old() | ::view-transition-new() |
|---|---|---|
| Visual state | Before the document update. | After the document update. |
| Representation | Static captured snapshot. | Live representation of the updated state. |
| Typical animation | Fade out. | Fade in. |
| Parent | ::view-transition-image-pair() |
::view-transition-image-pair() |
| When generated | When an old state exists. | When a new state exists. |
For example:
::view-transition-old(featured-card) {
animation: 300ms ease-in both fade-out-old;
}
::view-transition-new(featured-card) {
animation: 300ms ease-out both fade-in-new;
}
These rules use separate animations for the outgoing and incoming states.
The corresponding keyframes must also be defined.
When an element exists only in the new state, the browser generates the new representation without a corresponding old representation.
When an element exists only in the old state, the new representation is omitted.
Using View Transition Classes
The view-transition-class property allows multiple transition groups to share the same styling identifier.
Each element still needs its own transition name.
For example:
.card-one {
view-transition-name: card-one;
view-transition-class: cards;
}
.card-two {
view-transition-name: card-two;
view-transition-class: cards;
}
The two cards have unique transition names but share the transition class cards.
Their new representations can be styled together:
::view-transition-new(.cards) {
animation-duration: 500ms;
}
The dot before cards identifies a View Transition class selector.
A specific named group can receive a different animation:
::view-transition-new(card-one) {
animation-duration: 700ms;
}
This allows shared styling while preserving control over individual transitions.
View Transition classes are an advanced feature and should be checked for browser compatibility separately from basic View Transitions.
Supported CSS Properties
The ::view-transition-new() pseudo-element behaves as replaced content and supports applicable CSS properties for animation, visual effects, and image positioning.
| Property | Purpose |
|---|---|
animation |
Defines the animation applied to the new visual state. |
animation-duration |
Controls how long the animation takes. |
animation-timing-function |
Controls animation easing. |
opacity |
Controls transparency. |
transform |
Applies movement, scaling, or rotation. |
transform-origin |
Sets the origin for transformations. |
object-fit |
Controls how the visual representation fits its box. |
object-position |
Controls positioning within the replaced element's box. |
filter |
Applies visual effects. |
clip-path |
Clips the new visual representation for reveal effects. |
mix-blend-mode |
Controls how the new representation blends with other content. |
For example:
::view-transition-new(featured-card) {
animation-duration: 500ms;
object-fit: cover;
object-position: center;
}
This customizes the incoming animation duration and the visual representation's fitting behavior.
Changing properties that the browser uses for default animations may alter or override the generated transition effects.
Limitations
The ::view-transition-new() pseudo-element has several limitations.
- It exists only during an active View Transition.
- It does not initiate a transition by itself.
- It is generated only when a corresponding new visual state exists.
- It is always a child of a
::view-transition-image-pair()pseudo-element. - It does not contain child pseudo-elements.
- It does not permanently modify the underlying HTML element.
- Custom animations can override the browser's default cross-fade behavior.
- Changes to sizing, positioning, and blending can interfere with automatic transition rendering.
- Cross-document transitions have additional browser and navigation requirements.
- Advanced View Transition features may have different browser compatibility requirements.
For example, the following CSS does not create a transition by itself:
::view-transition-new(featured-card) {
animation-duration: 500ms;
}
A View Transition must be active, and the browser must generate a new visual representation for the named group.
Use view-transition-name and an appropriate transition mechanism to create the required conditions.
Accessibility Considerations
Animations that reveal updated content should be clear and comfortable for users.
Follow these accessibility practices:
- Respect the user's reduced-motion preference.
- Avoid rapid flashing or excessive scaling.
- Keep fade-in effects short and predictable.
- Ensure text remains readable throughout the animation.
- Preserve keyboard focus when the document changes.
- Do not use animation alone to communicate essential information.
- Ensure the updated content remains usable without View Transitions.
- Test animations at different zoom levels and viewport sizes.
For example, minimize animation durations when reduced motion is preferred:
@media (prefers-reduced-motion: reduce) {
::view-transition-group(*),
::view-transition-old(*),
::view-transition-new(*) {
animation-duration: 0.01ms;
}
}
For same-document transitions, JavaScript can also skip the animation entirely:
const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (document.startViewTransition && !reduceMotion) {
document.startViewTransition(updatePage);
} else {
updatePage();
}
This updates the document immediately when reduced motion is preferred or the API is unavailable.
Browser Support
The ::view-transition-new() pseudo-element has a Baseline Newly available status, with support across the latest major browsers since October 2025.
It is supported in current versions of Chrome, Edge, Firefox, Safari, and other browsers implementing CSS View Transitions.
Older browser versions may not support the feature.
Same-document and cross-document View Transitions have separate compatibility requirements.
To check whether a browser recognizes the selector:
@supports selector(::view-transition-new(root)) {
::view-transition-new(root) {
animation-duration: 500ms;
}
}
This applies the declaration only when the selector is recognized.
It does not start a transition or guarantee that a new representation exists.
For same-document transitions, provide a fallback when the JavaScript API is unavailable:
if (document.startViewTransition) {
document.startViewTransition(updatePage);
} else {
updatePage();
}
For current compatibility information, visit Can I Use? and search for View Transitions API.
Check support for advanced features separately when using them in production.
Specifications
The ::view-transition-new() pseudo-element is defined in the CSS View Transitions Module Level 1 .
The specification defines the pseudo-element as a generated representation of the new visual state during a View Transition.
It is rendered as replaced content within the corresponding ::view-transition-image-pair().
Related features include ::view-transition-old(), ::view-transition-group(), ::view-transition-image-pair(), the view-transition-name property, and the View Transitions API.
