React Router maps browser URLs to React UI without reloading the whole application. BrowserRouter owns history, while Routes and Route define the matching UI.
Use Link for user navigation, useNavigate after actions, useParams for dynamic segments, and Outlet for nested layouts.
Production routing also needs a wildcard 404 route and server fallback so direct URL refreshes return the React application.
React Router is the most common routing library for React applications. It allows users to move between different pages or views without reloading the entire browser page. This is called client-side routing.
In a traditional multi-page website, clicking a link usually requests a new HTML page from the server. In a React single-page application, React Router updates the URL and changes which components are shown, while the app stays loaded in the browser.
This makes navigation feel faster and smoother, and it helps React apps behave more like desktop applications.
To use React Router in a normal React app, install react-router-dom. Then wrap the app with BrowserRouter.
npm install react-router-dom
import ReactDOM from 'react-dom/client'
import { BrowserRouter } from 'react-router-dom'
import App from './App'
ReactDOM.createRoot(document.getElementById('root')).render(
<BrowserRouter>
<App />
</BrowserRouter>
)
Routes tell React Router which component should be rendered for a given URL. In React Router v6, routes are usually defined with Routes and Route.
import { Routes, Route } from 'react-router-dom'
function Home() {
return <h1>Home Page</h1>
}
function About() {
return <h1>About Page</h1>
}
function Contact() {
return <h1>Contact Page</h1>
}
function App() {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
</Routes>
)
}
In React Router, you normally use Link instead of a plain a tag for internal navigation. A plain anchor triggers a full page reload, while Link performs client-side navigation.
NavLink is similar to Link, but it can style the active route automatically. That makes it very useful for menus and navigation bars.
import { Link, NavLink } from 'react-router-dom'
function Navbar() {
return (
<nav>
<Link to="/">Home</Link>
<NavLink
to="/about"
className={({ isActive }) => isActive ? 'active-link' : ''}
>
About
</NavLink>
<NavLink to="/contact">Contact</NavLink>
</nav>
)
}
Many apps share a common layout across several pages, such as a header, sidebar, and footer. React Router supports this with nested routes and the Outlet component.
import { Routes, Route, Outlet } from 'react-router-dom'
function Layout() {
return (
<div>
<header>My Website</header>
<main>
<Outlet />
</main>
</div>
)
}
function Home() {
return <h2>Home</h2>
}
function About() {
return <h2>About</h2>
}
function App() {
return (
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route path="about" element={<About />} />
</Route>
</Routes>
)
}
Route parameters allow the URL to include dynamic values. For example, /users/5 and /users/9 can both use the same route pattern /users/:id.
import { Route, Routes, useParams } from 'react-router-dom'
function UserDetail() {
const { id } = useParams()
return <h2>User ID: {id}</h2>
}
function App() {
return (
<Routes>
<Route path="/users/:id" element={<UserDetail />} />
</Routes>
)
}
Sometimes navigation should happen after an action such as logging in, saving data, or submitting a form. In those cases, you can navigate in code using the useNavigate hook.
import { useNavigate } from 'react-router-dom'
function LoginForm() {
const navigate = useNavigate()
const handleLogin = () => {
// pretend login succeeded
navigate('/dashboard')
}
return <button onClick={handleLogin}>Login</button>
}
Some pages use query strings such as ?q=react&page=2. React Router provides useSearchParams to read and update those values.
import { useSearchParams } from 'react-router-dom'
function SearchPage() {
const [searchParams, setSearchParams] = useSearchParams()
const query = searchParams.get('q') || ''
return (
<div>
<input
value={query}
onChange={(e) => setSearchParams({ q: e.target.value })}
placeholder="Search..."
/>
<p>Current query: {query}</p>
</div>
)
}
Protected routes gate a screen behind an authentication check. In React Router, the route usually renders its element only when the session is valid; otherwise it redirects to sign-in or shows an access state that explains why the page is unavailable.
import { Navigate } from 'react-router-dom'
function ProtectedRoute({ isLoggedIn, children }) {
if (!isLoggedIn) {
return <Navigate to="/login" replace />
}
return children
}
function App() {
const isLoggedIn = false
return (
<Routes>
<Route
path="/dashboard"
element={
<ProtectedRoute isLoggedIn={isLoggedIn}>
<Dashboard />
</ProtectedRoute>
}
/>
</Routes>
)
}
A wildcard route with * can be used to show a "Page Not Found" screen when no other route matches.
function NotFound() {
return <h2>404 - Page Not Found</h2>
}
function App() {
return (
<Routes>
<Route path="*" element={<NotFound />} />
</Routes>
)
}
React Router gives React applications meaningful URLs and smooth navigation without full page reloads. It helps organize an application into screens, supports layouts, route parameters, query strings, protected routes, and not found pages, and makes large React apps much easier to structure.
Once you understand the core pieces such as BrowserRouter, Routes, Route, Link, NavLink, Outlet, and the routing hooks, you can build multi-page React experiences with confidence.
import { BrowserRouter, Link, Outlet, Route, Routes, useParams } from "react-router-dom";
function Layout() {
return <><nav><Link to="/">Home</Link> <Link to="/users/42">User</Link></nav><Outlet /></>;
}
function User() {
const { id } = useParams();
return <h2>User {id}</h2>;
}
export default function App() {
return <BrowserRouter><Routes><Route element={<Layout />}>
<Route index element={<h2>Home</h2>} />
<Route path="users/:id" element={<User />} />
<Route path="*" element={<h2>Not found</h2>} />
</Route></Routes></BrowserRouter>;
}
Explore 500+ free tutorials across 20+ languages and frameworks.