I need to define user pages (Home, Cows, Reports, ...) once and make them accessible to AppUser + Admin under "/" with UserLayout, and also accessible to Admin under "/admin/user/*" but rendered inside AdminLayout.
When I try to reuse the same route array in both places, I sometimes get UserLayout showing for "/admin/user/" or matching conflicts due to absolute vs relative paths. I'm looking for an idiomatic pattern to mount the same relative child routes under two parents (two layouts) without duplication and without layout leaks.
I mounted user pages only under "/" inside UserLayout, guarded for both roles (AppUser + Admin). I mounted admin-only pages under "/admin/*" inside AdminLayout, guarded for Admin only.
Router (what I did):
router.jsx (essentials)
{
element: <RequireAuth />,
children: [
{
path: "/",
element: <UserLayout />,
children: [
{
element: <RequireRole allowed={[Roles.AppUser, Roles.Admin]} />,
children: [
{ path: "/", element: <Home /> },
{ path: "/cows", element: <AnimalManagement /> },
// ...other user pages under "/"
],
},
],
},
{
path: "/admin",
element: <RequireRole allowed={[Roles.Admin]} />,
children: [
{
path: "/admin",
element: <AdminLayout />,
children: [
{ path: "/admin/dashboard", element: <AdminDashboard /> },
// ...other admin-only pages under "/admin"
],
},
],
},
],
}
Expectation:
When an Admin clicks user pages from the admin sidebar, I want those pages to render inside AdminLayout (so the admin shell/Sidebar stays visible), even though the same pages are also available at "/" for both roles.
Actual result:
Because user pages exist only under "/", navigating to them shows UserLayout, not AdminLayout. I’m looking for an React-Router/React-Router-DOM v6 pattern to mount the same user routes under "/admin/user/*" (alias) so they render inside AdminLayout—without duplicating the route definitions or breaking role guards.
1 Answer 1
If I am understanding your question correctly, you are trying to render a set of "common" routes both under the root "/" path and also under the "/admin" path.
The first main issue I see in your router definition is that you are specifying absolute route paths everywhere. This makes it incredibly difficult, probably impossible, to allow using the routes anywhere but where they exactly match and specify. You should be using relative paths. E.G. paths that do not start with the "/" character. This will allow you to move a route around anywhere and it will always match relative to its parent route.
A second issue is defining paths on your layout routes. While this is perfectly fine and can work in most cases, you will typically want to avoid adding a path prop to your layout routes as you want them to typically only enforce UI layout and not participate in routing.
Here is my suggestion:
- Create a definition of your "common routes", i.e. the routes you wish to render under multiple parent routes.
const commonUserAndAdminRoutes = [
{ path: "cows", element: <AnimalManagement /> },
{ path: "sheep", element: /* .... */ },
{ path: "pigs", element: /* .... */ },
// ...etc...
];
- Update the router to use relative route paths and spread in the common routes where you want/need them.
const router = createBrowserRouter([
{
// pathless route!
element: <RequireAuth />,
children: [
{
// pathless route!
element: <RequireRole allowed={[Roles.AppUser, Roles.Admin]} />,
children: [
{
// pathless route!
element: <UserLayout />,
children: [
// index route matches "/"
{ index: true, element: <Home /> },
// common routes match relative to "/"
...commonUserAndAdminRoutes,
// ...other user pages under "/"
],
},
],
},
{
path: "admin",
element: <RequireRole allowed={[Roles.Admin]} />,
children: [
{
// pathless route!
element: <AdminLayout />,
children: [
// index route matches "/admin" and redirects to "/admin/dashboard"
{ index: true, element: <Navigate to="dashboard" replace /> },
// matches "/admin/dashboard"
{ path: "dashboard", element: <AdminDashboard /> },
// common routes match relative to "/admin"
...commonUserAndAdminRoutes,
// ...other admin-only pages under "/admin"
],
},
],
},
],
},
]);
If you want admins to see the same AdminLayout on "/" and other non-"/admin" routes (instead of UserLayout) then my suggestion would be create a dynamic layout route component that renders either of UserLayout or AdminLayout depending on the role or whatever criteria you need.
Example:
const UserOrAdminLayout = () => {
const isAdmin = /* compute this */;
return isAdmin
? <AdminLayout />
: <UserLayout />;
};
const router = createBrowserRouter([
{
element: <RequireAuth />,
children: [
{
element: <RequireRole allowed={[Roles.AppUser, Roles.Admin]} />,
children: [
{
element: <UserOrAdminLayout />,
children: [
{ index: true, element: <Home /> },
{ path: "/cows", element: <AnimalManagement /> },
// ...other user pages under "/"
],
},
],
},
{
path: "admin",
element: <RequireRole allowed={[Roles.Admin]} />,
children: [
{
element: <AdminLayout />,
children: [
{ index: true, element: <Navigate to="dashboard" replace /> },
{ path: "dashboard", element: <AdminDashboard /> },
// ...other admin-only pages under "/admin"
],
},
],
},
],
},
]);
Comments
Explore related questions
See similar questions with these tags.
react-next-router. Simple folder based route like next js app router. Support Layout and group layout concept also. You can see example here also i just wrapped app router concept in react router