Plaintext Engineering

Complete Guide to React Router v7: Modes, Routing Methods, and Advanced Examples

Sep 2, 2025 • 5 min read


React Router is the go-to routing solution for React applications, supporting seamless navigation between components and URLs in single-page applications (SPAs). Version 7 streamlines routing APIs and introduces multi-strategy router modes for different levels of control and features.

This comprehensive tutorial covers React Router v7 starting from scratch and dives into:

The three routing modes and when to use each

Different routing methods including file-based and config-based routing

Setting up basic to advanced routes with type safety, loaders, and layouts

More complex routing examples including nested layouts, dynamic/semi-dynamic routes, and catch-alls

React Router v7: Understanding the Three Modes of Usage

React Router v7 offers three main modes to choose from, depending on how much control or automation you want:

ModeDescriptionUse Case
DeclarativeBasic routing with <BrowserRouter>, <Routes>, <Route>. Supports matching URLs to components, navigation, and active states.Simple SPAs or apps needing custom routing control.
Data ModeAdds data APIs like loader, action, useFetcher allowing declarative data loading and mutations with route definitions outside JSX.Data-driven apps needing built-in loading/spinner states, forms, and mutations.
Framework ModeBuilt on Data Mode with filesystem routes, route modules with type-safety, SSR support, code splitting, and more, often integrated into modern frameworks with plugins.Full-featured apps requiring SSR, streaming, and code splitting with strong conventions.

Learn more about modes

Different Routing Methods & Configurations

There are multiple ways to define routes in React Router v7 depending on the mode and app architecture:

1. Declarative Routing (Inside JSX)

Using <Routes> and <Route> inside a React component:

import { BrowserRouter, Routes, Route } from "react-router-dom";

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="about" element={<About />} />
      </Routes>
    </BrowserRouter>
  );
}

2. Config-Based Routing (Data Mode)

Routes are defined as an array of route objects outside components, used with createBrowserRouter(), and rendered via <RouterProvider>:

import { createBrowserRouter, RouterProvider } from "react-router-dom";

const router = createBrowserRouter([
  {
    path: "/",
    element: <Root />,
    loader: fetchData,
    children: [
      { index: true, element: <Home /> },
      { path: "about", element: <About /> }
    ]
  }
]);

function App() {
  return <RouterProvider router={router} />;
}

3. Filesystem Routing (Framework Mode)

Common in framework mode (e.g., Remix or React Router framework integration), routes are defined based on your file structure, e.g.,

app/routes.ts

[
  index("./home.tsx"),
  route("about", "./about.tsx"),
  layout("./dashboard.tsx", [
    route("settings", "./settings.tsx"),
  ])
] satisfies RouteConfig

Dynamic routes use parameterized filenames ([userId].tsx) or route patterns (route(“users/:userId”, …)).

More on routing conventions and modules

Step-by-Step: Basic React Router v7 Setup and Examples

Installation

npm install react-router-dom@7

Basic Routes with URL Parameters

import { BrowserRouter, Routes, Route, Link, useParams } from 'react-router-dom';

function User() {
  const { userId } = useParams();
  return <h2>User ID: {userId}</h2>;
}

function App() {
  return (
    <BrowserRouter>
      <nav>
        <Link to="/">Home</Link> | <Link to="/user/123">User 123</Link>
      </nav>
      <Routes>
        <Route path="/" element={<h1>Home Page</h1>} />
        <Route path="/user/:userId" element={<User />} />
      </Routes>
    </BrowserRouter>
  );
}

Nested Routes and Layouts Using <Outlet>

Define a parent route with children using nested <Routes> and render children in the parent via <Outlet>:

import { Outlet, Link, Routes, Route } from "react-router-dom";

function DashboardLayout() {
  return (
    <div>
      <nav>
        <Link to="home">Home</Link> | <Link to="settings">Settings</Link>
      </nav>
      <Outlet />
    </div>
  );
}

function DashboardHome() {
  return <h3>Dashboard Home</h3>;
}

function DashboardSettings() {
  return <h3>Settings</h3>;
}

function App() {
  return (
    <Routes>
      <Route path="/dashboard" element={<DashboardLayout />}>
        <Route path="home" element={<DashboardHome />} />
        <Route path="settings" element={<DashboardSettings />} />
      </Route>
    </Routes>
  );
}

Dynamic and Optional Segments

<Routes>
  <Route path="products/:productId" element={<Product />} />
  <Route path="users/:userId/edit?" element={<UserEditor />} />
</Routes>

:productId is required.

:userId/edit? means /users/123 and /users/123/edit both match.

Catch-All (Splat) Routes

Define catch-all routes with * to match unknown URLs:

<Routes>
  <Route path="files/*" element={<FileViewer />} />
  <Route path="*" element={<NotFound />} />
</Routes>

/files/documents/reports will be matched by files/* and splat (rest of path) can be accessed from params params["*"].

Advanced Example: Data Loading & Actions in Data Mode

Using loaders and actions in route modules to fetch data and handle mutations:

// routes/products.tsx - route module

import { useLoaderData, Form } from "react-router-dom";

export async function loader() {
  const products = await fetchProducts();
  return products;
}

export async function action({ request }) {
  const formData = await request.formData();
  await createProduct(formData.get("name"));
  return null;
}

export default function Products() {
  const products = useLoaderData();

  return (
    <>
      <ul>
        {products.map((p) => (
          <li key={p.id}>{p.name}</li>
        ))}
      </ul>
      <Form method="post">
        <input name="name" placeholder="New product" />
        <button type="submit">Add</button>
      </Form>
    </>
  );
}

Summary Table: Common React Router v7 APIs by Mode

FeatureDeclarativeDataFramework
<Routes>, <Route>
Route Config Arrays
Filesystem Routing
Loaders (Data Fetch)
Actions (Mutations)
useNavigate
useParams
<Outlet>
Code Splitting
SSR/SSG Support

Closing Notes

React Router v7 is versatile with layered modes from basic declarative routing to fully-featured framework integrations with SSR and data loading. This flexibility means you can start simple but scale your routing architecture with growing app complexity.

Feel free to explore route modules and loaders for dynamic data-driven apps or filesystem routing for convention-based organizations.

Happy routing with React Router v7!

Sources

Related articles