Next.js 44: Intercepting Routes
easy⏱ 5 mincoursenextjs
Two page.tsx files, one URL
Both app/@modal/(..)photo/[id]/page.tsx and app/photo/[id]/page.tsx can render for /photo/3 — which one wins depends on how you arrived. The (..) segments mean 'go up N levels in the URL', letting the modal route live in a different folder than the URL it intercepts.
app/
@modal/
(..)photo/[id]/page.tsx // rendered as a modal, intercepts /photo/[id]
photo/[id]/
page.tsx // full page — used on direct visit/refresh
layout.tsx // renders {children} AND {modal}
page.tsx // the gallery
// app/layout.tsx
export default function Layout({
children,
modal,
}: {
children: React.ReactNode;
modal: React.ReactNode;
}) {
return (
<html lang="en">
<body>
{children}
{modal}
</body>
</html>
);
}
Open, then 'refresh'
Click a photo to open it in the modal — the gallery should stay visible behind it. Then click Simulate refresh on this URL to see what a real reload of /photo/id would show: just the full page, gallery gone, because the interception only ever applies to client-side navigation.
Why this pattern exists
Intercepting routes give you shareable, bookmarkable, refresh-safe URLs for content that's usually shown as a modal (photo lightboxes, login dialogs, quick-view product cards) — without hand-rolling modal routing logic. The URL always reflects what's on screen either way.