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