Skip to content
FLAVIO COPES
flaviocopes.com
2026

Introduction to React Router

By

Learn the current React Router declarative API with BrowserRouter, Routes, Route, Link, URL parameters, and programmatic navigation.

~~~

React Router connects the browser URL to a React interface. It lets a single-page application render a different component for each path while keeping normal links, browser history, and back and forward navigation.

This guide uses React Router’s Declarative mode, the smallest setup for adding client-side routing to an existing React application.

React Router also provides Data mode and Framework mode for applications that need route loaders, actions, code splitting, and other framework features.

Install React Router

Install the current package:

npm install react-router

Older projects may import browser APIs from react-router-dom. Current React Router documentation uses react-router for new declarative applications.

Add BrowserRouter

Wrap the application with BrowserRouter at the root:

import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import { BrowserRouter } from 'react-router'
import App from './App.jsx'

createRoot(document.getElementById('root')).render(
  <StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </StrictMode>,
)

BrowserRouter uses the browser History API to keep the interface and URL in sync.

Define routes

Put Route elements inside Routes:

import { Route, Routes } from 'react-router'
import Home from './pages/Home.jsx'
import About from './pages/About.jsx'
import NotFound from './pages/NotFound.jsx'

export default function App() {
  return (
    <Routes>
      <Route path="/" element={<Home />} />
      <Route path="/about" element={<About />} />
      <Route path="*" element={<NotFound />} />
    </Routes>
  )
}

Routes chooses the best matching route for the current URL. The element prop contains the React element to render.

You do not need the old exact prop. Current route matching handles this without it.

Use Link for normal navigation inside the application:

import { Link } from 'react-router'

export default function Navigation() {
  return (
    <nav>
      <Link to="/">Home</Link>
      {' '}
      <Link to="/about">About</Link>
    </nav>
  )
}

Link renders an accessible link and prevents a full document reload for routes handled by the application.

Use a regular <a> element when linking to another site or to a download that should trigger normal browser navigation.

NavLink works like Link but also exposes whether the link is active or pending:

import { NavLink } from 'react-router'

<NavLink
  to="/about"
  className={({ isActive }) => isActive ? 'active' : undefined}
>
  About
</NavLink>

Read URL parameters

A path segment beginning with : is dynamic:

<Route path="/posts/:postId" element={<Post />} />

Read the value with useParams():

import { useParams } from 'react-router'

export default function Post() {
  const { postId } = useParams()

  return <h1>Post {postId}</h1>
}

Visiting /posts/42 gives postId the string value "42".

URL values are user input. Validate a parameter before using it in a query or sending it to a server.

Create nested routes

Routes can mirror a layout hierarchy:

import { Outlet, Route, Routes } from 'react-router'

function DashboardLayout() {
  return (
    <>
      <h1>Dashboard</h1>
      <Outlet />
    </>
  )
}

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

The child route renders where the parent places <Outlet />.

The index route matches /dashboard. The settings route matches /dashboard/settings.

Read the current location

useLocation() returns information about the current location:

import { useLocation } from 'react-router'

function CurrentPath() {
  const location = useLocation()

  return <p>Current path: {location.pathname}</p>
}

The object also contains search, hash, state, and a location key.

Use URLSearchParams to read a small number of query-string values, or React Router’s useSearchParams() hook when you also need to update them.

Use useNavigate() when navigation happens after an action, such as completing a form:

import { useNavigate } from 'react-router'

function LoginForm() {
  const navigate = useNavigate()

  async function handleSubmit(event) {
    event.preventDefault()

    const success = await logIn()

    if (success) {
      navigate('/dashboard', { replace: true })
    }
  }

  return <form onSubmit={handleSubmit}>{/* fields */}</form>
}

Prefer Link or NavLink when the user is simply choosing where to go. Links provide better keyboard, accessibility, and browser behavior.

Configure the web server

BrowserRouter creates URLs such as /about, but the browser can also request that URL directly after a refresh.

Your hosting server must serve the application’s HTML entry file for client-side routes that do not match a real static file. Without that fallback, a direct visit to /about may return a 404 even though in-app navigation works.

See the official React Router guides for Declarative mode installation, routing, navigation, and the available modes.

Tagged: React · All topics
~~~

Related posts about react: