Next.js Discord

Discord Forum

Problem with Next.js Interception route

Answered
Razorbill posted this in #help-forum
Open in Discord
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?
Answered by Brown bear
You want 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.
View full answer

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 [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?
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-routes
I 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 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?
Brown bear
In this case, I think what I explained earlier is correct. So, you would:
1. make a folder work-requests/@modal
2. move your [codename]/[id] into that folder
3. add a default.tsx to that folder that renders nothing
4. 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 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.
And for this you have to use interception route.
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.
@West African Lion work-requests page or work-requests/[codename]/[id] page with hidden modal?
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
@Razorbill 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
@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?
@West African Lion Click to see attachment
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
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
@West African Lion @modal/(.)[id]/page.tsx
RazorbillOP
@modal/[codename]/[id]/page.tsx

Here's the modal content I want to show over /work-requests/page.tsx
Brown bear
You want 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
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. 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 it
the files are commented at the top where they go
West African Lion
So @Brown bear, is it working in your case?
Brown bear
yes.
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.
@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.