Routes, Links & Navigation
React itself has no built-in router. React Router v6 is the standard choice for client-side routing in most React apps. It maps URL paths to components, enables navigation without full page reloads, and provides hooks for reading and updating the URL.
Install React Router with:
npm install react-router-dom
Wrapping Your App in a Router
Wrap your root component in BrowserRouter (or RouterProvider with the newer data router API). All routing hooks and components must be inside this context:
import { BrowserRouter } from 'react-router-dom'
function Root() {
return (
<BrowserRouter>
<App />
</BrowserRouter>
)
}Routes and Route
Routes is the container that looks at the current URL and renders the first matching Route. Each Route maps a path to an element:
import { Routes, Route } from 'react-router-dom'
function App() {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/blog" element={<Blog />} />
<Route path="/contact" element={<Contact />} />
{/* Catch-all: shown when nothing else matches */}
<Route path="*" element={<NotFound />} />
</Routes>
)
}Index Routes
An index route is the default child rendered when the parent path matches but no child path does. Add the index prop instead of a path:
<Routes>
<Route path="/dashboard" element={<DashboardLayout />}>
<Route index element={<DashboardHome />} /> {/* /dashboard */}
<Route path="stats" element={<Stats />} /> {/* /dashboard/stats */}
<Route path="reports" element={<Reports />} />{/* /dashboard/reports */}
</Route>
</Routes>Link — Navigation Without Reloads
Never use a plain <a href> for internal navigation — it causes a full page reload and loses React state. Use Link from React Router instead:
import { Link } from 'react-router-dom'
function Nav() {
return (
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
<Link to="/blog">Blog</Link>
<Link to="/contact">Contact</Link>
</nav>
)
}NavLink — Active Styling
NavLink extends Link with automatic active-state awareness. It adds an active class (or applies an inline style) when the current URL matches the link's to path:
import { NavLink } from 'react-router-dom'
function MainNav() {
return (
<nav>
{/* className can be a function that receives { isActive } */}
<NavLink
to="/"
className={({ isActive }) => isActive ? 'nav-link active' : 'nav-link'}
end // 'end' prevents '/' matching every path
>
Home
</NavLink>
<NavLink
to="/blog"
style={({ isActive }) => ({
fontWeight: isActive ? 'bold' : 'normal',
color: isActive ? 'tomato' : 'inherit',
})}
>
Blog
</NavLink>
</nav>
)
}Navigate — Declarative Redirects
The Navigate component redirects as part of rendering — useful for conditional redirects based on auth or derived state:
import { Navigate } from 'react-router-dom'
function Dashboard() {
const { isLoggedIn } = useAuth()
if (!isLoggedIn) {
// Redirect to /login without leaving a history entry
return <Navigate to="/login" replace />
}
return <DashboardContent />
}Complete Multi-Page App
import { BrowserRouter, Routes, Route, NavLink, Outlet } from 'react-router-dom'
// Pages
function Home() { return <h1>Home</h1> }
function About() { return <h1>About</h1> }
function Blog() { return <h1>Blog</h1> }
function NotFound(){ return <h1>404 — Page not found</h1> }
// Shared navigation layout
function Layout() {
return (
<div>
<header>
<nav style={{ display: 'flex', gap: 16 }}>
<NavLink to="/" end className={({ isActive }) => isActive ? 'active' : ''}>
Home
</NavLink>
<NavLink to="/about" className={({ isActive }) => isActive ? 'active' : ''}>
About
</NavLink>
<NavLink to="/blog" className={({ isActive }) => isActive ? 'active' : ''}>
Blog
</NavLink>
</nav>
</header>
<main>
{/* Child routes render here */}
<Outlet />
</main>
</div>
)
}
function App() {
return (
<BrowserRouter>
<Routes>
<Route element={<Layout />}>
<Route index element={<Home />} />
<Route path="about" element={<About />} />
<Route path="blog" element={<Blog />} />
<Route path="*" element={<NotFound />} />
</Route>
</Routes>
</BrowserRouter>
)
}Relative vs Absolute Paths
to="/about"— absolute path, always navigates to/about.to="about"— relative path, appended to the current route segment.to="../settings"— go up one segment, then tosettings.Inside nested routes, prefer relative paths so parent path changes do not break child links.