Problem with Next.js Interception route
Answered
Razorbill posted this in #help-forum
RazorbillOP
I am using next.js v15 app router.
I have a button in page.tsx
When clicking that button I want to show this route [id]/page.tsx as modal on the page.
When I refresh the page, I want to show the modal, not standalone page.
How can I implement this approach?
I have a button in page.tsx
When clicking that button I want to show this route [id]/page.tsx as modal on the page.
When I refresh the page, I want to show the modal, not standalone page.
How can I implement this approach?
Answered by Brown bear
You want
with
work-requests/page.tsx
to render for sub-routes as well, i.e. under this modal. I think the simplest way to do it is by moving it's contents to a layout file, as this is the purpose of the layout file. You could do so by doing something like this:app/
├─ work-requests/
│ ├─ layout.tsx
│ ├─ page.tsx
│ ├─ [codename]/[id]/
│ │ ├─ page.tsx
with
work-requests/layout.tsx
containing your current work-requests/page.tsx
contents and also rendering children
, work-requests/page.tsx
rendering nothing, but allowing the route to be accessed (i.e., the url example.com/work-requests
renders work-requests/layout.tsx
and work-requests/page.tsx
), and the modal in [codename]/[id]/page.tsx
.86 Replies
Brown bear
It sounds like you don't want an interception route at all. When you refresh the page, you want it to show the modal on top of the same
[id]/page.tsx
?West African Lion
In that case, you don't need to use interception route, btw if you wanna still use that, you can implement the modal(open) in the default.tsx.
Brown bear
If that is the case, the modal route needs to know the
in the default parallel route, render nothing. In the modal/ one, render the modal.
[id]
as well. I think the best way to do so is with parallel routes, putting the modal at /[id]/modal
or something like that.app/
├─ [id]/
│ ├─ layout.tsx
│ ├─ page.tsx
│ ├─ @modal/
│ │ ├─ default.tsx
│ │ ├─ modal/
│ │ │ ├─ page.tsx
in the default parallel route, render nothing. In the modal/ one, render the modal.
RazorbillOP
@Brown bear
Why I have to use modal/page.tsx? Can I use page.tsx directly in @modal?
Why I have to use modal/page.tsx? Can I use page.tsx directly in @modal?
Brown bear
no; @modal creates the parallel route, meaning
[id]/layout.tsx
will get an additional param called modal
containing whatever routes match in @modal
. That's why you have @modal/default.tsx
and @modal/modal/page.tsx
. The route is what maters for the URL. if you wanted the modal at [id]/login
or [id]/edit
you would use @modal/login/page.tsx
or @modal/edit/page.tsx
instead.I forgot to mention the
[id]/layout.tsx
file. You would change it to render both children
and modal
.RazorbillOP
What will be the url to access that modal in that case?
Brown bear
[id]/modal
, [id]/login
, or [id]/edit
depending on the contents of the @modal
folder. See the parallel routes page for more info https://nextjs.org/docs/app/building-your-application/routing/parallel-routesI also may be wrong here; I'm not sure the behavior of parallel routes on the
[id]/page.tsx
West African Lion
Maybe the reason why you want to use interception route is route.
@Brown bear, in your case, the modal should be removed in the @modal.
app/
├─ [id]/
│ ├─ layout.tsx
│ ├─ page.tsx
│ ├─ @modal/
│ │ ├─ page.tsx
Brown bear
in that case, the modal would always show.
RazorbillOP
This is the my project structure
Brown bear
Unless you added conditional rendering to it or something. Prince, can you explain what you want the end result to be?
RazorbillOP
So I want to show modal over work-requests/page.tsx
Brown bear
And when they refresh?
RazorbillOP
Still shows modal when refresh
Brown bear
still shows the modal over the same
[codename]/[id]
?or, just shows the modal over the work requests page?
RazorbillOP
[codename]/[id] is modal route. I want to show that modal on work-requests/page.tsx when refresh
Brown bear
ok. So, user is on
work-requests
, goes to work-requests/[codename]/[id]
, and you want it to show a modal over the top of the work-requests
page. Then, when they refresh or directly visit work-requests/[codename]/[id]
, it should still show the modal over the work-requests
page?RazorbillOP
Corret
West African Lion
@Razorbill, so in that case, what do you want to show when the user click history back?
Brown bear
In this case, I think what I explained earlier is correct. So, you would:
1. make a folder
2. move your
3. add a
4. Add
1. make a folder
work-requests/@modal
2. move your
[codename]/[id]
into that folder3. add a
default.tsx
to that folder that renders nothing4. Add
work-requests/layout.tsx
, which will recieve props { children, modal}
and render both.West African Lion
work-requests page or work-requests/[codename]/[id] page with hidden modal?
Brown bear
When you visit
When you visit
work-requests
, the layout will recieve whatever work-requests/@modal/default.tsx
renders, and will recieve work-requests/page.tsx
for children
.When you visit
work-requests/[codename]/[id]
, layout will recieve whatever work-requests/[codename]/[id]/page.tsx
renders for modal
, and work-requests/page.tsx
for children
.West African Lion
So if you want to show the modal still even the user refresh the current page.
You have to implement the opened modal in the default.tsx.
You have to implement the opened modal in the default.tsx.
And for this you have to use interception route.
RazorbillOP
I tried this but it didn't work
Brown bear
I don't think that's what they're asking Demi. It sounds like there is no modal when they are on
work-requests
and only when at work-requests/[codename]/[id]
should a modal appear, specifically ABOVE whatever work-requests
is showing, and should remain even when refreshing.West African Lion
@Brown bear, you forgot to mention about the interception route.
RazorbillOP
I want to show work-requests/page.tsx when history back
Brown bear
Demi, I dont think an interception route is appropriate, because it should render the SAME thing regardless of how it's reached.
West African Lion
Let's point that the route.
We can solve the modal opened when the user refresh using the default.tsx.
Default, the default.tsx returns nulll.
But in this case, @Razorbill should render the opened modal in the default.tsx
Except this, the others are same as interception route.
Of course, @Razorbill have to use parallel route too.
RazorbillOP
I did like this but getting 404 error
Brown bear
getting 404 on what URL?
oh oh,
RazorbillOP
/work-requests/[codename]/[id]
West African Lion
Just a sec, I will show you something.
Brown bear
default.tsx should go directly in
@modal
RazorbillOP
Still showing 404 page
West African Lion
Brown bear
ah, I think that I was wrong on how
children
behaves. Could you rename work-requests/page.tsx
to work-requests/default.tsx
?RazorbillOP
In this approach, it shows [codename]/[id]/page.tsx when refresh, and shows @modal/(.)/[id]/page.tsx when navigating. I don't want that
West African Lion
@modal/(.)/[id]/page.tsx ?
@modal/(.)[id]/page.tsx
RazorbillOP
That doesn't work
It shows 404 page on /work-requests
It shows 404 page on /work-requests
Brown bear
ok. If you duplicate
page.tsx
to default.tsx
; Also, I think we may be overcomplicating this. let me write something out.RazorbillOP
I don't think I have to update /work-requests/page.tsx
There's no problem with that file
Brown bear
yeah, just copy that file
to
work-requests/default.tsx
and if it works, you can refactor it's contents to share it between both. I'm not 100% sure tho
RazorbillOP
But it doesn't work
@modal/[codename]/[id]/page.tsx
Here's the modal content I want to show over /work-requests/page.tsx
Here's the modal content I want to show over /work-requests/page.tsx
Brown bear
You want
with
work-requests/page.tsx
to render for sub-routes as well, i.e. under this modal. I think the simplest way to do it is by moving it's contents to a layout file, as this is the purpose of the layout file. You could do so by doing something like this:app/
├─ work-requests/
│ ├─ layout.tsx
│ ├─ page.tsx
│ ├─ [codename]/[id]/
│ │ ├─ page.tsx
with
work-requests/layout.tsx
containing your current work-requests/page.tsx
contents and also rendering children
, work-requests/page.tsx
rendering nothing, but allowing the route to be accessed (i.e., the url example.com/work-requests
renders work-requests/layout.tsx
and work-requests/page.tsx
), and the modal in [codename]/[id]/page.tsx
.Answer
RazorbillOP
lol, if I have another page under work-requests, then how? Use another sub-routes for that? 🤣
Brown bear
If work-requests has other routes which should NOT render the work requests page, for example
work-requests/options
or seomething of the sort, you could use a route group so that the layout will not render for those, and will only render for the other routes.app/
├─ work-requests/
│ ├─ (modal)
│ │ ├─ layout.tsx
│ │ ├─ page.tsx
│ │ ├─ [codename]/[id]/
│ │ │ ├─ page.tsx
│ ├─ (non-modal)
│ │ ├─ ... other subroutes
and
(non-modal)
shouldn't contain any matching routes for work-requests/
; only for subroutes like work-requests/options
etc.RazorbillOP
Showing page content in layout.tsx is not the best practice. I hope there's another way
Brown bear
You could make
work-requests/page.tsx
a optional catch-all route, and then programatically show the modal. i.e. work-requests/[[...path]]/page.tsx
Brown bear
I jsut went and tested it myself, this is what worked for me.
RazorbillOP
can you please show what you updated?
Brown bear
1.
2.
localhost:3000/test
shows the contents of /test/page.tsx
and /test/@modal/default.tsx
2.
localhost:3000/test/modal
shows the contents of /test/modal/page.tsx
and /test/@modal/modal/page.tsx
I modified it to use a common component for both
/test/page.tsx
and /test/modal/page.tsx
because that's what you want to do. I'll upload a gist and share itthe files are commented at the top where they go
West African Lion
So @Brown bear, is it working in your case?
Brown bear
yes.
RazorbillOP
I followed that @Brown bear
Brown bear
Here's one more way to do it. This would be if you want a common backdrop page for the modal, and potentially you have multiple modals. I've attached screenshots showing the behavior
West African Lion
@Brown bear, please check this code.
West African Lion
Using this way, we can implement the purpose also, but in this case, we can use the advantages of interception route such as route back, and show modal and full screen modal when the user refresh.
Brown bear
I think your implementation is fine, but not what Prince asked for. Prince explicitly wants the behavior to be the SAME, regardless of whether the user gets to the modal from work-requests or directly navigates to it (i.e, on refresh). In the case of what Prince wants, intercept routes are not applicable, because the behavior needs to be the same, regardless of how the user reaches the route.
West African Lion
Yes, agree.
But using this way, we can acheive @Razorbill's purpose also.
After refreshing.
Using this, we can improve ux.