Next.js Discord

Discord Forum

Problem with Next.js Interception route

Answered
Razorbill posted this in #help-forum
Open in Discord
Avatar
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

Avatar
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?
Avatar
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.
Avatar
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.
Avatar
RazorbillOP
@Brown bear
Why I have to use modal/page.tsx? Can I use page.tsx directly in @modal?
Avatar
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.
Avatar
RazorbillOP
What will be the url to access that modal in that case?
Avatar
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
Avatar
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
Avatar
Brown bear
in that case, the modal would always show.
Avatar
RazorbillOP
This is the my project structure
Image
Avatar
Brown bear
Unless you added conditional rendering to it or something. Prince, can you explain what you want the end result to be?
Avatar
RazorbillOP
So I want to show modal over work-requests/page.tsx
Avatar
Brown bear
And when they refresh?
Avatar
RazorbillOP
Still shows modal when refresh
Avatar
Brown bear
still shows the modal over the same [codename]/[id]?
or, just shows the modal over the work requests page?
Avatar
RazorbillOP
[codename]/[id] is modal route. I want to show that modal on work-requests/page.tsx when refresh
Avatar
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?
Avatar
RazorbillOP
Corret
Avatar
West African Lion
@Razorbill, so in that case, what do you want to show when the user click history back?
Avatar
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.
Avatar
West African Lion
work-requests page or work-requests/[codename]/[id] page with hidden modal?
Avatar
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.
Avatar
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.
Avatar
RazorbillOP
I tried this but it didn't work
Avatar
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.
Avatar
West African Lion
@Brown bear, you forgot to mention about the interception route.
Avatar
RazorbillOP
I want to show work-requests/page.tsx when history back
Avatar
Brown bear
Demi, I dont think an interception route is appropriate, because it should render the SAME thing regardless of how it's reached.
Avatar
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.
Avatar
RazorbillOP
I did like this but getting 404 error
Image
Avatar
Brown bear
getting 404 on what URL?
oh oh,
Avatar
RazorbillOP
/work-requests/[codename]/[id]
Avatar
West African Lion
Just a sec, I will show you something.
Avatar
Brown bear
default.tsx should go directly in @modal
Avatar
RazorbillOP
Still showing 404 page
Avatar
West African Lion
Image
Avatar
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?
Avatar
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
Avatar
West African Lion
@modal/(.)/[id]/page.tsx ?
@modal/(.)[id]/page.tsx
Avatar
RazorbillOP
That doesn't work
It shows 404 page on /work-requests
Avatar
Brown bear
ok. If you duplicate page.tsx to default.tsx; Also, I think we may be overcomplicating this. let me write something out.
Avatar
RazorbillOP
I don't think I have to update /work-requests/page.tsx
There's no problem with that file
Avatar
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
Avatar
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
Avatar
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
Avatar
RazorbillOP
lol, if I have another page under work-requests, then how? Use another sub-routes for that? 🤣
Avatar
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.
Avatar
RazorbillOP
Showing page content in layout.tsx is not the best practice. I hope there's another way
Avatar
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
Avatar
Brown bear
Image
I jsut went and tested it myself, this is what worked for me.
Avatar
RazorbillOP
can you please show what you updated?
Avatar
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
Avatar
West African Lion
So @Brown bear, is it working in your case?
Avatar
Brown bear
yes.
Avatar
RazorbillOP
I followed that @Brown bear
Avatar
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
Image
Image
Image
Avatar
West African Lion
@Brown bear, please check this code.
Image
Avatar
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.
Avatar
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.
Avatar
West African Lion
Yes, agree.
But using this way, we can acheive @Razorbill's purpose also.
Image
After refreshing.
Image
Using this, we can improve ux.