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="/" />,
},
]);
element
→ Defines what gets rendered at that route
-
element
is the React node/component that should be rendered when the URL matches the route’spath
. - Think of it as the container or layout for that route.
👉 Example:
{
path: '/auth',
element: <AuthLayout />, // Renders the Auth layout wrapper
}
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’selement
. - 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 />,
},
],
}
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 /> },
],
}
What’s happening here?
-
element
=<AdminRoute><AdminLayout /></AdminRoute>
- That means before rendering
<AdminLayout />
, theAdminRoute
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 />
-
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)