Search code examples
javascriptreactjsreact-routerreact-router-dom

How to render the same path for different layout-routes in React Router v6?


I am trying to render a specific route for two different layout routes. Basically this route must render for the public and private layouts, but with the same path.

Something like this

createBrowserRouter([
  {
    element: <PublicLayout />,
    children: [
      // other routes in public layout
      {
        path: '/legal/*',
        element: <Legal />,
      },
    ],
  },
  {
    element: <PrivateLayout />,
    children: [
      // other routes in private layout
      {
        path: '/legal/*',
        element: <Legal />,
      },
    ],
  },
])

The Legal component fits in both layouts, but in this configuration only the public layout will be rendered. The splat in the path is because Legal has descendent routes.

I've tried a wrapper component but it just doesn't render.

export default function LegalRouter() {
  const isOnline = true

  return (
    <Routes>
      <Route element={isOnline ? <Layout /> : <PublicLayout />}>
        <Route element={<Legal />} />
      </Route>
    </Routes>
  )
}

Solution

  • You can't render two routes on the same path within the same Routes component, so you'll likely need to abstract a new route guard component that conditionally renders a "Public" or "Private" wrapper component. You can't just directly use PublicLayout and PrivateLayout here though since you don't want to do any redirection but instead just want to swap out the UI, e.g. the "UI/layout" components from each.

    Example:

    const PublicPrivateLayout = () => {
      const /* condition */ = /* compute condition value */;
    
      const Wrapper = /* condition */ ? PublicWrapper : PrivateWrapper;
    
      return (
        <Wrapper>
          <Outlet />
        </Wrapper>
      );
    };
    
    createBrowserRouter([
      {
        element: <PublicLayout />,
        children: [
          // public-only routes
        ],
      },
      {
        element: <PrivateLayout />,
        children: [
          // private-only routes
        ],
      },
      {
        element: <PublicPrivateLayout />,
        children: [
          // public or private routes
          {
            path: '/legal/*',
            element: <Legal />,
          },
        ],
      },
    ]);