RFC: (Route exit transitions) Custom component for wrapping TemplateContext.Provider array #56594
evankirkiles
started this conversation in
Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Goals
OuterLayoutRouter
's route-keyed array ofTemplate
s as children, as we claim to do in the docs for templates.Background
Current Behavior
Currently, page exit transitions are not supported in
appDir
. There's no way for libraries likeframer-motion
placed inlayout.tsx
to monitor the changing array of keyedTemplateContext.Provider
s—e.g.templates
—which is something we previously claimed could be done inlayout.tsx
, and is currently implied by the docs:Instead, there is the necessary intermediary of
OuterLayoutRouter
, which handles caching of each subroute. The DOM looks (abstractly) like this:As the
layout.tsx
gets an opaqueOuterLayoutRouter
view of any slots it provides, there's no way for us to keep a previous route around past its lifetime in order to animate it out. And, astemplate.tsx
is mounted for every route, we of course can't manage the route's own lifecycle there, either.Motivation
I think I speak for a lot of web designers / developers when I say that this is probably one of the largest issues keeping me on the
pages
directory—the ability to use route exit transitions for a smoother user experience. It would be a massive boon for theappDir
to have this functionality implemented, especially if taking into accountappDir
's ability for parallel routing... Aglue
component or something of the sort providing an easy drop-in for scoped exit transitions at each parallel route's slot would be a game-changer.Proposal
Somehow, we need to bridge the gap from userland code to the keyed array of
TemplateContext.Provider
s if we want to persist exiting routes as is usually done withframer.motion
. My immediate idea is just to add a new type of client component called aGlue
component, placed in aglue.tsx
file, which can be inserted inside theOuterLayoutRouter
at the correct position:This would enable the following structure, assuming a user uses
framer-motion
's<AnimatePresence />
as theirGlue
component:Example
Draft PR with the above: #56591
The above proposal works with very minimal code changes, though with some current quirks related to how parallel routes that aren't the implicit
@children
slot are keyed:Screen.Recording.2023-10-08.at.3.05.00.PM.mov
Concerns
I understand that adding in a new file component is a huge thing to do. However, with the way
"use client"
works, and the client-side-only nature of anyGlue
component, making it its own file separate fromlayout.tsx
andtemplate.tsx
for now was the quickest way to get the PoC out.An alternative approach could be to simply add this
Glue
component as a custom export oftemplate.tsx
, turning the file into what I feel like it ultimately should be—custom wiring between a route and its parent layout. Then, the default export oftemplate.tsx
would be remounted on every page navigation, whereas someexport const Glue = function() { }
would persist across templates much likelayout.tsx
does. However, this would cause issues with styling, as the styles fromtemplate.tsx
are rightfully loaded in the child tree of theGlue
component, where the template is, and so wouldn't be accessible from whatever HTML element(s)Glue
is. And again, thetemplate.tsx
would then have to be a client component.I also don't like doing the same from the other end, e.g.
layout.tsx
, because I think it'd be better to leave the door open to more granular templating, e.g. differentGlue
components for different parallel routes with their owntemplate.tsx
's, or some other more slot-based approach. Also, this'd force yourlayout
to be a client component with"use client"
as well.Beta Was this translation helpful? Give feedback.
All reactions