Building a Photo-Modal Flow with Soft Navigation
Combine interception and parallel routes to open items in a modal yet deep-link on refresh.
Why Modals Break Deep-Linking
Traditional modal implementations render a dialog on top of the current page. This creates a fundamental problem: when a user shares the URL or refreshes the browser, the modal disappears — there is no route change, so no persistent URL state exists.
Next.js 15 solves this with two advanced routing features working in tandem:
- Intercepting Routes — catch a navigation and render a different UI in the current context
- Parallel Routes — render two route segments simultaneously in the same layout
Together they let you open a photo in a modal with a proper URL (e.g. /photos/42) while keeping the grid visible behind it. On a hard refresh, the same URL shows the full-page photo view instead.
The File Structure You Need
The pattern requires a specific directory layout inside your app/ folder. Here is the structure for a photo gallery:
app/photos/page.tsx— the photo grid (list view)app/photos/[id]/page.tsx— the standalone full-page photo detailapp/@modal/(.)photos/[id]/page.tsx— the intercepted modal versionapp/layout.tsx— root layout that accepts themodalslot
The @modal prefix declares a parallel route slot. The (.) prefix on the intercepting segment tells Next.js: intercept navigations that go to photos/[id] at the same depth in the URL tree.
This dual existence — a real page at photos/[id] and an intercepted version at @modal/(.)photos/[id] — is the entire secret.
All lessons in this course
- Parallel Routes with Named Slots and Default Segments
- Intercepting Routes for Shared Modal Experiences
- Conditional Slot Rendering for Dashboards and Tabs
- Building a Photo-Modal Flow with Soft Navigation