How do I render components with different layouts/elements using react-router-dom v6
If I understand your question, you are wanting to render the nav and sidebar on the non-login route. For this you can create a layout component that renders them and an outlet for the nested routes.
Using nested routes
import { Outlet } from 'react-router-dom';
const AppLayout = () => (
<>
<NavBar />
<SideBar />
<main className={styles["main--container"]}>
<div className={styles["main--content"]}>
<Outlet /> // <-- nested routes rendered here
</div>
</main>
</>
);
const App = () => {
return (
<>
<Routes>
<Route path="/login" element={<LoginPage />} />
<Route element={<AppLayout />} >
<Route path="/" element={<Dashboard />} /> // <-- nested routes
</Route>
</Routes>
</>
);
};
Using a routes configuration and useRoutes
hook
const routesConfig = [
{
path: "/login",
element: <LoginPage />,
},
{
element: <AppLayout />,
children: [
{
path: "/",
element: <Dashboard />,
},
],
},
];
...
import { useRoutes } from 'react-router-dom';
const App = () => {
const routes = useRoutes(routesConfig);
return routes;
};
Using a routes configuration and data routers (introduced in v6.4.0)
const routesConfig = [
{
path: "/login",
element: <LoginPage />,
},
{
element: <AppLayout />,
children: [
{
path: "/",
element: <Dashboard />,
},
],
},
];
...
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
const router = createBrowserRouter(routesConfig);
const App = () => {
return <RouterProvider router={router} />;
};
React Router v6 : How to render multiple component inside and outside a div with the same path
Part of the issue is that you are rendering multiple identical paths, i.e. two "/"
paths and two nested index paths. This won't work.
In react-router-dom
v6 you can create what are called layout components. The layout components can render your headers and footers, sidebars, drawers, and general content layout elements, and importantly an Outlet
component for the nested/wrapped Route
components to be rendered into.
Example:
import { Outlet } from 'react-router-dom';
const AppLayout = ({ admin }) => admin ? (
<>
<Topbar />
<div className="container">
<Sidebar />
<Outlet />
</div>
</>
) : null;
Render the layout component into a Route
wrapping the routes you want to be rendered into the specific layout.
<Routes>
<Route path="/login" element={<Login/>} />
<Route element={<AppLayout admin={admin} />}>
<Route index element={<Home />} />
<Route path="/users" element={<UserList />} />
<Route path="/user/:userId" element={<User />} />
<Route path="/newUser" element={<NewUser />} />
<Route path="/productList" element={<ProductList />} />
<Route path="/product/:productId" element={<Product />} />
<Route path="/newProduct" element={<NewProduct />} />
</Route>
</Routes>
Page layout broken in React Router v6
Layout
should render an Outlet
for the children Routes
to be rendered into.
import { Outlet } from 'react-router-dom';
function Layout() {
return (
<div className="layout">
<Header />
<SidePanel />
<div className="main" style={{ marginTop: "100px" }}>
<Outlet />
</div>
</div>
);
}
Outlet
An
<Outlet>
should be used in parent route elements to render their
child route elements. This allows nested UI to show up when child
routes are rendered.
React Router v6 shared layouts
you have to render an <Outlet />
for inside your layout element to specify where the active child route should be mounted.
<Routes>
<Route path="/" element={<p>Home</p>} />
<Route element={<div style={{ background: 'red' }} > <Outlet /> </div>}>
<Route path="/login" element={<p>Login</p>} />
</Route>
</Routes>
How to implement multiple route with single container or layout in react-router-dom v6
If you've "common" layout containers you want to share/render with multiple routes/routed components then it's common to have each layout render nested routes into an Outlet
component.
Example:
import { Outlet } from 'react-router-dom';
const LoginLayout = () => (
<div /* layout props & styling */ >
{/* local layout UI */}
<Outlet /> // <-- nested routes rendered here
</div>
);
const AdminLayout = () => (
<div /* layout props & styling */ >
{/* local layout UI */}
<Outlet />
</div>
);
...
<Routes>
<Route element={<LoginLayout />}>
<Route path="/" element={<SignInForm />} />
<Route path="/signin" element={<SignInForm />} />
<Route path="/newpassword" element={<NewPassword />} />
<Route path="/phoneverification" element={<PhoneVerification />} />
<Route path="/continuewithphone" element={<ContWithPhone />} />
<Route path="/resetpassword" element={<ResetPassword />} />
<Route
path="/confirm-resetpassword"
element={<ConfirmResetPassword />}
/>
</Route>
<Route element={<AdminLayout />}>
// Routes here
</Route>
</Routes>
react-router v6 double rendering components
The GalleryCard
and About
components are rendered twice because they are rendered in two places.
index
<Routes>
<Route path="/" element={<App />}>
<Route path="/about" element={<About />} /> // <-- here
<Route path="/gallery" element={<Gallery />} /> // <-- here
</Route>
</Routes>
App
const App = () => {
const background = require("../../assets/images/45-degree-fabric-light.png")
return (
<div className="App">
<div className='background'>
<img src={background} className='background' alt="background" />
</div>
<NavBar/>
<Divider className='divider' textAlign="left">GALLERY</Divider>
<div className='card-container'>
<GalleryCard/> // <-- and here
</div>
<Divider className='divider' textAlign="left">ABOUT</Divider>
<About/> // <-- and here
</div>
);
}
Remove them from App
, replace them with an Outlet
component so the nested routes render out there in their place.
import { Outlet } from 'react-router-dom';
...
const App = () => {
const background = require("../../assets/images/45-degree-fabric-light.png")
return (
<div className="App">
<div className='background'>
<img src={background} className='background' alt="background" />
</div>
<NavBar/>
<Outlet />
</div>
);
}
Move the divider and title to the components.
React Router Dom, render a component only for some routes
Quick Solution:
You could simply do like below, adding the Nav
where you want. I'm not sure if you can know the path in App
, since it's not wrapped inside the Router
.
import { BrowserRouter as Router, Routes, Route, matchPath } from "react-router-dom";
import Nav from "./components/Nav/Nav";
import Home from "./components/Home/Home";
import Contributors from "./components/Contributors/Contributors";
const App = () => {
return (
<Router>
<Routes>
<Route path="/" exact element={<Home />} />
<Route path="/contributors" element={<><Nav /><Contributors /></>} />
</Routes>
</Router>
);
}
export default App;
Improvement:
And if you want to take it further, instead of doing like above, you could set up a Layout
component, like this:
import { Outlet } from "react-router-dom";
import Nav from "../Nav/Nav";
const Layout () => {
return (
<>
<Nav />
<Outlet />
</>
);
};
export default Layout;
And render the routes where you want the Nav
trough the Layout
:
import { BrowserRouter as Router, Routes, Route, matchPath } from "react-router-dom";
import Home from "./components/Home/Home";
import Contributors from "./components/Contributors/Contributors";
import Layout from "./components/Layout/Layout";
const App = () => {
return (
<Router>
<Routes>
<Route path="/" exact element={<Home />} />
<Route element={<Layout />}>
<Route path="/contributors" element={<Contributors />} />
</Route>
</Routes>
</Router>
);
}
export default App;
How to add Navbar and a Sidebar inside the React Router v6 Routes?
Have you tried something like:
return (
<div className="App">
<BrowserRouter>
{logged ? (
<>
<Navbar />
<div className="screens-container">
<Sidebar />
<div className='screens-section-container'>
<Routes>
<Route path='/' element={<Home />} />
<Route path='/customers' element={<Customers />} />
<Route path='/products' element={<Products/>}/>
<Route path='/transactions' element={<Transactions />} />
<Route path='/users' element={<Users />} />
</Routes>
</div>
</div>
</>
): (
<Routes>
<Route path='/' element={<Login />} />
</Routes>
)}
</BrowserRouter>
</div>
);
Related Topics
Why Was the Arguments.Callee.Caller Property Deprecated in JavaScript
JavaScript - Href VS Onclick for Callback Function on Hyperlink
How Is Almost Everything in JavaScript an Object
Node.Js Plans to Support Import/Export Es6 (Ecmascript 2015) Modules
Open a New Tab in the Background
"Innerhtml += ..." VS "Appendchild(Txtnode)"
Form Serialize JavaScript (No Framework)
How to Replace While Loops with a Functional Programming Alternative Without Tail Call Optimization
How to Get Progress from Xmlhttprequest
Http Headers in Websockets Client API
Can't Bind to 'Ngmodel' Since It Isn't a Known Property of 'Input'
How to Get the Scrollbar Position with JavaScript
Empty Arrays Seem to Equal True and False at the Same Time
Using Jquery's Ajax Method to Retrieve Images as a Blob
Dynamically Add Script Tag with Src That May Include Document.Write
Get Elements by Attribute When Queryselectorall Is Not Available Without Using Libraries