DEV Community

Cristian Sifuentes
Cristian Sifuentes

Posted on

Understanding `children` vs `element` in React Router’s `createBrowserRouter` (with Protected Routes)

Understanding  raw `children` endraw  vs  raw `element` endraw  in React Router’s  raw `createBrowserRouter` endraw  (with Protected Routes)

Understanding children vs element in React Router’s createBrowserRouter (with Protected Routes)

When working with React Router v6+, you’ve probably noticed two key props inside createBrowserRouter:

  • element
  • children

At first glance, they look similar — but they serve very different purposes. Understanding this distinction is essential for building scalable routing systems, especially when you add layouts and protected routes (auth/admin).

In this blog, we’ll break down the difference, show real-world examples, and explain how element and children combine to create a flexible router tree.


Quick Refresher: createBrowserRouter

Here’s a simplified version of your router setup:

import { createBrowserRouter, Navigate } from 'react-router';
import { ShopLayout } from './shop/layouts/ShopLayout';
import { HomePage } from './shop/pages/home/HomePage';
import { ProductPage } from './shop/pages/product/ProductPage';
import { GenderPage } from './shop/pages/gender/GenderPage';

export const appRouter = createBrowserRouter([
  {
    path: '/',
    element: <ShopLayout />,   // ✅ Layout (element)
    children: [
      {
        index: true,
        element: <HomePage />, // ✅ Nested route (child)
      },
      {
        path: 'product/:idSlug',
        element: <ProductPage />,
      },
      {
        path: 'gender/:gender',
        element: <GenderPage />,
      },
    ],
  },
  {
    path: '*',
    element: <Navigate to="/" />,
  },
]);
Enter fullscreen mode Exit fullscreen mode

element → Defines what gets rendered at that route

  • element is the React node/component that should be rendered when the URL matches the route’s path.
  • Think of it as the container or layout for that route.

👉 Example:

{
  path: '/auth',
  element: <AuthLayout />, // Renders the Auth layout wrapper
}
Enter fullscreen mode Exit fullscreen mode

If the user navigates to /auth, React Router renders <AuthLayout />.


children → Defines nested routes inside the layout

  • children represent nested routes that live inside the parent’s element.
  • They are rendered inside the parent’s <Outlet />.

👉 Example:

{
  path: '/auth',
  element: <AuthLayout />,
  children: [
    {
      index: true,
      element: <Navigate to="/auth/login" />,
    },
    {
      path: 'login',
      element: <LoginPage />,
    },
    {
      path: 'register',
      element: <RegisterPage />,
    },
  ],
}
Enter fullscreen mode Exit fullscreen mode

Here:

  • /auth/login → Renders <LoginPage /> inside <AuthLayout />.
  • /auth/register → Renders <RegisterPage /> inside <AuthLayout />.

This is possible because <AuthLayout /> likely uses <Outlet /> somewhere inside.


Protected Routes with element

You can wrap layouts or pages inside route guards (like AdminRoute or NotAuthenticatedRoute).

👉 Example:

{
  path: '/admin',
  element: (
    <AdminRoute>
      <AdminLayout />
    </AdminRoute>
  ),
  children: [
    { index: true, element: <DashboardPage /> },
    { path: 'products', element: <AdminProductsPage /> },
    { path: 'products/:id', element: <AdminProductPage /> },
  ],
}
Enter fullscreen mode Exit fullscreen mode

What’s happening here?

  • element = <AdminRoute><AdminLayout /></AdminRoute>
  • That means before rendering <AdminLayout />, the AdminRoute checks if the user is authenticated and authorized.
  • If yes → renders the layout and its children.
  • If no → redirects to login or shows an error page.

Visual Mental Model

Think of it like this:

/auth
  ├── element: <AuthLayout />
  └── children:
        • /login → <LoginPage />
        • /register → <RegisterPage />

/admin
  ├── element: <AdminRoute><AdminLayout /></AdminRoute>
  └── children:
        • / → <DashboardPage />
        • /products → <AdminProductsPage />
        • /products/:id → <AdminProductPage />
Enter fullscreen mode Exit fullscreen mode
  • element = the wrapping layout/guard
  • children = the actual content pages, injected via <Outlet />

Pro Tips 🚀

✅ Use element for:

  • Layouts (ShopLayout, AuthLayout, AdminLayout)
  • Route guards (AdminRoute, NotAuthenticatedRoute)

✅ Use children for:

  • Nested routes rendered inside a parent layout.
  • Structuring multi-level apps (shop, auth, admin, etc.).

✅ Always add an index: true child for default pages.

✅ Use <Navigate /> for redirects in element.


Conclusion

The difference between element vs children is subtle but powerful:

  • element = the wrapper or layout (what renders immediately at that path).
  • children = the nested routes inside that layout (rendered through <Outlet />).

When combined with ProtectedRoutes, this pattern gives you a scalable and secure routing architecture for modern React apps.

Next time you’re structuring routes, ask yourself:

👉 Is this a wrapper/layout/guard? → Use element.

👉 Is this a page inside a layout? → Use children.


✍️ Written by: Cristian Sifuentes — Full-stack developer & AI/JS enthusiast, passionate about React, TypeScript, and scalable architectures.

Tags: #react #frontend #routing #programming

Top comments (0)