React supports slots, a mechanism that enables component composition over inheritance. Instead of prop drilling, slots let a React component pass down unknown chunks of JSX to its children. Any children along the hierarchy chain who do not care what is being passed down will happily hand the JSX parcels to their own children. Only the interested parties will then unpack the parcel and decide what to do with it, either to fill some holes or unpick the props useful to them.

The children prop is a use case of the mechanism. Under the hood, there is nothing special about the children prop - any other props can be used to pass arbitrary ReactNode JSX bundles around, too. This is especially useful when the JSX passed down is dynamic or conditional. For example, the widgets appearing in a sidebar may differ based on the type of pages or whether a user is signed in.

Next.js supports parallel routing that can load one or more pages (routes) simultaneously or conditionally, not surprisingly, powered by the slot pattern. By convention, Next.js defines a named slot with a @foldernaem directory.

./
└── app
    β”œβ”€β”€ @auth
    β”‚Β Β  β”œβ”€β”€ login
    β”‚Β Β  β”‚Β Β  └── page.tsx
    β”‚Β Β  └── signup
    β”‚Β Β      └── page.tsx
    β”œβ”€β”€ layout.tsx
    └── page.tsx

Slots areΒ notΒ route segments andΒ do not affect the URL structure. The file pathΒ /@auth/loginΒ is accessible viaΒ /login.

import { getUser } from '@/lib/auth';
 
export default function Layout({ 
  dashboard, 
  login,
}: { 
  dashboard: React.ReactNode,
  login: React.ReactNode,
}) { 
  const isLoggedIn = getUser();
  return isLoggedIn ? dashboard : login;
};