Introduction
One of the most underappreciated yet powerful features in Next.js is its routing system, particularly parallel and intercepting routes. These features are extensively used in media-heavy websites like Dribbble, Pinterest, and Pexels. If you've noticed how clicking an image on these sites opens a modal while simultaneously updating the URL, and how refreshing that URL shows a full page - that's the magic of these routing features in action.
Parallel Routes
What Are Parallel Routes?
Parallel routes allow you to render multiple pages simultaneously within the same layout. Instead of treating components as simple React components (like <Profile/>
and <Analytics/>
), you can treat them as separate pages using the @
prefix notation.
Example Use Case: Dashboard
Consider a dashboard that needs to display both analytics and user profile information:
app/
├── dashboard/
│ ├── layout.tsx
│ ├── page.tsx
│ ├── @analytics/
│ │ └── page.tsx
│ └── @profile/
│ └── page.tsx
In your layout.tsx
:
export default function DashboardLayout({
children,
profile,
analytics,
}: {
children: React.ReactNode
analytics: React.ReactNode
profile: React.ReactNode
}) {
return (
<>
{children}
{profile}
{analytics}
</>
)
}
Important Notes About Parallel Routes
Parallel routes are treated as "slots" and are dependent on their parent route
Direct navigation to
/profile
or/analytics
won't work as these are slots, not standalone routesThey're particularly useful for conditional rendering based on authentication status or other conditions
Intercepting Routes
What Are Intercepting Routes?
Intercepting routes allow you to show content from another route while maintaining the current context. This is what enables the modal-like behavior seen on image gallery websites.
Example: Image Gallery Implementation
Basic Folder Structure
app/
├── page.tsx # Home page with image gallery
├── image/
│ └── [id]/
│ └── page.tsx # Full page view
└── @modal/
├── default.tsx # Default modal state
└── (.)image/
└── [id]/
└── page.tsx # Modal view of image
Understanding the Convention
The
@modal
folder creates a parallel route for modal contentThe
(.)
notation in(.)image
indicates an intercepting routeUse
(..)
if targeting a parent routeUse
(...)
if targeting a root route similar to relative path convention
Implementation Notes
1. The content logic in both image/[id]/page.tsx
and @modal/(.)image/[id]/page.tsx
should be similar
2. For modal functionality:
// In @modal/(.)image/[id]/page.tsx
import { useRouter } from 'next/navigation'
export default function ImageModal() {
const router = useRouter()
return (
<div className="modal">
{/* Your modal content */}
<button onClick={() => router.back()}>Close</button>
</div>
)
}
Need a production-ready modal component for your Next.js intercepting routes? https://dev-components.vercel.app/components/modal
Good Practices
1. Always include a default.tsx
in modal routes to handle the default state
2. Use consistent naming conventions for parallel routes
3. Keep modal and full-page versions of content in sync
4. Handle loading and error states appropriately
Conclusion
Understanding parallel and intercepting routes is crucial for building modern web applications with sophisticated navigation patterns. They enable complex UI interactions while maintaining clean URLs and proper navigation history.