Routes are configured as the first argument to createBrowserRouter. At a minimum, you need a path and component:
import { createBrowserRouter } from "react-router"; function Root() { return <h1>Hello world</h1>; } const router = createBrowserRouter([ { path: "/", Component: Root }, ]); Here is a larger sample route config:
createBrowserRouter([ { path: "/", Component: Root, children: [ { index: true, Component: Home }, { path: "about", Component: About }, { path: "auth", Component: AuthLayout, children: [ { path: "login", Component: Login }, { path: "register", Component: Register }, ], }, { path: "concerts", children: [ { index: true, Component: ConcertsHome }, { path: ":city", Component: ConcertsCity }, { path: "trending", Component: ConcertsTrending }, ], }, ], }, ]); Route objects define the behavior of a route beyond just the path and component, like data loading and actions. We'll go into more detail in the Route Object guide, but here's a quick example of a loader.
import { createBrowserRouter, useLoaderData, } from "react-router"; createBrowserRouter([ { path: "/teams/:teamId", loader: async ({ params }) => { let team = await fetchTeam(params.teamId); return { name: team.name }; }, Component: Team, }, ]); function Team() { let data = useLoaderData(); return <h1>{data.name}</h1>; } Routes can be nested inside parent routes through children.
createBrowserRouter([ { path: "/dashboard", Component: Dashboard, children: [ { index: true, Component: Home }, { path: "settings", Component: Settings }, ], }, ]); The path of the parent is automatically included in the child, so this config creates both "/dashboard" and "/dashboard/settings" URLs.
Child routes are rendered through the <Outlet/> in the parent route.
import { Outlet } from "react-router"; export default function Dashboard() { return ( <div> <h1>Dashboard</h1> {/* will either be <Home> or <Settings> */} <Outlet /> </div> ); } Omitting the path in a route creates new Nested Routes for its children without adding any segments to the URL.
createBrowserRouter([ { // no path on this parent route, just the component Component: MarketingLayout, children: [ { index: true, Component: Home }, { path: "contact", Component: Contact }, ], }, { path: "projects", children: [ { index: true, Component: ProjectsHome }, { // again, no path, just a component for the layout Component: ProjectLayout, children: [ { path: ":pid", Component: Project }, { path: ":pid/edit", Component: EditProject }, ], }, ], }, ]); Note that:
Home and Contact will be rendered into the MarketingLayout outletProject and EditProject will be rendered into the ProjectLayout outlet while ProjectsHome will not.Index routes are defined by setting index: true on a route object without a path.
{ index: true, Component: Home } Index routes render into their parent's Outlet at their parent's URL (like a default child route).
import { createBrowserRouter } from "react-router"; createBrowserRouter([ // renders at "/" { index: true, Component: Home }, { Component: Dashboard, path: "/dashboard", children: [ // renders at "/dashboard" { index: true, Component: DashboardHome }, { path: "settings", Component: DashboardSettings }, ], }, ]); Note that index routes can't have children.
A route with just a path and no component creates a group of routes with a path prefix.
createBrowserRouter([ { // no component, just a path path: "/projects", children: [ { index: true, Component: ProjectsHome }, { path: ":pid", Component: Project }, { path: ":pid/edit", Component: EditProject }, ], }, ]); This creates the routes /projects, /projects/:pid, and /projects/:pid/edit without introducing a layout component.
If a path segment starts with : then it becomes a "dynamic segment". When the route matches the URL, the dynamic segment will be parsed from the URL and provided as params to other router APIs.
{ path: "teams/:teamId", loader: async ({ params }) => { // params are available in loaders/actions let team = await fetchTeam(params.teamId); return { name: team.name }; }, Component: Team, } import { useParams } from "react-router"; function Team() { // params are available in components through useParams let params = useParams(); // ... } You can have multiple dynamic segments in one route path:
{ path: "c/:categoryId/p/:productId"; } You can make a route segment optional by adding a ? to the end of the segment.
{ path: ":lang?/categories"; } You can have optional static segments, too:
{ path: "users/:userId/edit?"; } Also known as "catchall" and "star" segments. If a route path pattern ends with /* then it will match any characters following the /, including other / characters.
{ path: "files/*"; loader: async ({ params }) => { params["*"]; // will contain the remaining URL after files/ }; } You can destructure the *, you just have to assign it a new name. A common name is splat:
const { "*": splat } = params; Next: Route Object