Intercepting Routes Resolver
Hard · Routing
Intercepting routes load another route inside the current layout, typically as a modal: clicking a photo in /feed shows /photo/42 in a modal over the feed, while opening /photo/42 directly (or refreshing) shows the full photo page. Folder markers work like relative paths, but for route segments:
- (.) matches segments on the same level, (..) one level above, (..)(..) two levels above, (...) from the root app directory.
- Route segments ignore (group) folders and @slot folders: app/feed/@modal/(..)photo is at segment level /feed, so (..)photo means /photo.
Write resolveNavigation(pages, interceptors, nav). This is a simplified model of how Next.js turns interception folders into rewrites. pages and interceptors are file paths ending in /page.tsx (ignore other files in pages); nav is { from, to, type: "soft" | "hard" }.
- For each interceptor, take the app path (the file without app and /page.tsx, e.g. /feed/@modal/(..)photo/[id]). Find the first segment starting with a marker (check (..)(..), (.), (..), (...) in this order). Split the app path at that marker: the part before, with groups and slots removed, is the intercepting route (/feed, or / when empty); the part after is the rest (photo/[id]).
- The intercepted route: (.) is intercepting route + / + rest (just / + rest at the root); (..) drops the last segment of the intercepting route first; (..)(..) drops the last two; (...) is / + rest.
- (..) on the root intercepting route, or (..)(..) on a route with fewer than two segments, is invalid: return { error: "Invalid interception route: <app path>" } for the first invalid interceptor, whatever nav is.
- On a soft navigation, the first interceptor whose intercepting route matches from (the same segments, or any deeper path below it; / matches everything) and whose intercepted route matches to renders: { file, intercepted: true }. [param] segments match any one segment.
- Otherwise (hard navigation or no interceptor), render the normal page for to (groups removed, static segments preferred over [param]): { file, intercepted: false }, or null if none matches.