Render element above view transition
Unanswered
Leach's Storm-Petrel posted this in #help-forum
Leach's Storm-PetrelOP
I just updated to Next 16, and I wanted to try the new view transitions API to get some nicer page transitions. I wrapped the children in my main layout inside a ViewTransition component, and it works great, except for one detail - my Sonner (shadcn) toasts render partially above the page section of the layout, and since view transition captures are rendered in a separate layer above the DOM, the toasts get cut in half while the view transition animation is playing.
Is there a way to render the Sonner in such a way that the view transition capture renders below it?
Is there a way to render the Sonner in such a way that the view transition capture renders below it?
3 Replies
@Leach's Storm-Petrel I just updated to Next 16, and I wanted to try the new view transitions API to get some nicer page transitions. I wrapped the children in my main layout inside a ViewTransition component, and it works great, except for one detail - my Sonner (shadcn) toasts render partially above the page section of the layout, and since view transition captures are rendered in a separate layer above the DOM, the toasts get cut in half while the view transition animation is playing.
Is there a way to render the Sonner in such a way that the view transition capture renders below it?
Saltwater Crocodile
Hi @Leach's Storm-Petrel, This happens because Next.js View Transitions render the page snapshot in a separate compositor layer above the DOM. Sonner renders via a document.body, so during the transition part of the toast ends up behind the cptured layer and looks clipped.
The fix is to exclude the Sonner container from view transitions:
[data-sonner-toaster] {
view-transition-name: none;
}
alternatively, render the toaster outside the ViewTransition wrapper so it isn't caputred at all.
The fix is to exclude the Sonner container from view transitions:
[data-sonner-toaster] {
view-transition-name: none;
}
alternatively, render the toaster outside the ViewTransition wrapper so it isn't caputred at all.
@Saltwater Crocodile Hi <@286482224554049537>, This happens because Next.js View Transitions render the page snapshot in a separate compositor layer above the DOM. Sonner renders via a document.body, so during the transition part of the toast ends up behind the cptured layer and looks clipped.
The fix is to exclude the Sonner container from view transitions:
[data-sonner-toaster] {
view-transition-name: none;
}
alternatively, render the toaster outside the ViewTransition wrapper so it isn't caputred at all.
Leach's Storm-PetrelOP
The toaster is already rendered outside of the ViewTransition wrapper, it isn't captured. The issue is that the captured part is overlayed above the toaster, covering part of it.
I've tried explicitly setting the name to none (does nothing since it's already outside of the ViewTransition wrapper), as well as rendering the toaster in a separate view transition layer (doesn't render at all during transitions because the component doesn't have an explicit width and thus isn't captured, though it would interrupt animations anyway so it's not a solution)
I've tried explicitly setting the name to none (does nothing since it's already outside of the ViewTransition wrapper), as well as rendering the toaster in a separate view transition layer (doesn't render at all during transitions because the component doesn't have an explicit width and thus isn't captured, though it would interrupt animations anyway so it's not a solution)
Saltwater Crocodile
This isn't a capture issue, it's a stacking order problem. View Transitions render the root snapshot in a compositor layer above the DOM, so live UI like toasts can be visually covered even when rendered outside the ViewTransition wrapper.
The fix is to lower the ::view-transition-* (root) pseudo-elements via CSS and let overlays sit above them. Using z-index alone doesn’t work because the snapshot ignores normal DOM stacking context.
::view-transition-image-pair(root) {
z-index: 0;
}
::view-transition-old(root),
::view-transition-new(root) {
z-index: 0;
}
[data-sonner-toaster] {
position: fixed;
z-index: 1000;
}
The fix is to lower the ::view-transition-* (root) pseudo-elements via CSS and let overlays sit above them. Using z-index alone doesn’t work because the snapshot ignores normal DOM stacking context.
::view-transition-image-pair(root) {
z-index: 0;
}
::view-transition-old(root),
::view-transition-new(root) {
z-index: 0;
}
[data-sonner-toaster] {
position: fixed;
z-index: 1000;
}