React Router's navigation system rests on three pieces working together: the Routes container that picks the right view, individual Route definitions that map a URL to a component, and Link components that change the URL without a full page reload. This lesson covers how they fit together, plus the v5-to-v6 changes worth knowing.
1The <Routes> Container
In React Router v6, <Routes> acts as the container for every route definition in a section of the app. Whenever the current location changes, <Routes> examines all of its child <Route> elements and renders the one that best matches the URL.
Everything that maps a path to a component has to live inside a <Routes> container ā it's the piece that actually decides which branch of the UI gets rendered for the current location.
// Core Components: Routes, Route, and LinkThe Container
<Routes>
2Upgrading: <Switch> to <Routes>
Older React Router apps (v5) used a <Switch> component instead of <Routes>. They serve a similar purpose, but <Routes> is meaningfully smarter: <Switch> simply rendered the first route in the list whose path matched, so route order mattered.
<Routes> instead uses a scoring algorithm to find the most specific match among all children, regardless of the order they're written in ā a real improvement if you're maintaining or migrating a v5 codebase.
import { Routes, Route } from 'react-router-dom';
<Routes>
<Route path='/' element={<Home />} />
</Routes>Goodbye Switch
Hello Routes.
3Defining Individual Routes
Inside <Routes>, each <Route> component defines a single mapping: when the URL matches its path exactly, React Router renders the component passed to its element prop.
A typical app defines several of these side by side, like <Route path="/dashboard" element={<Dashboard />} /> and <Route path="/settings" element={<Settings />} />, and <Routes> picks whichever one matches the current location.
// v5: <Switch> --> v6: <Routes>The Mapping
URL -> Component
4element vs component
React Router v5 used a component prop on <Route>, passed as a bare component reference like component={Home}. v6 replaced this with an element prop that instead takes a JSX element, like element={<Home />}.
This change makes it much simpler to pass props directly to a routed component ā writing element={<Admin user={currentUser} />} just works, whereas the old component prop had no clean way to forward props like that.
import { Link } from 'react-router-dom';
<Link to='/about'>About Us</Link>element prop
Use JSX syntax.
5The <Link> Component
To navigate between routes, React Router provides the <Link> component. Visually and functionally, it looks like a standard HTML <a> tag, but it intercepts the click instead of letting the browser handle it.
Rather than requesting a whole new document from the server, <Link> uses the browser's History API to update the URL instantly on the client, re-rendering only the parts of the UI that actually need to change.
<NavLink
style={({ isActive }) => ({ color: isActive ? 'red' : 'black' })}
>
Home
</NavLink>The Link
Instant client-side navigation
6Why Not <a> Tags?
Using a plain <a href="/about"> for internal navigation causes the browser to perform a full page refresh. Every piece of in-memory React state ā component variables, form input, even a Redux store ā gets completely wiped out and reset when that happens.
Inside a single-page app, <a> tags should never be used for internal navigation; <Link> exists specifically to change the URL while preserving all of that in-memory state.
/* Routes & Links Module Completed */Protect State
Anchors destroy state.
7Step-by-Step Breakdown
Core Concepts. Building a navigation system in React requires three core elements: the Container (<Routes>), the Path Definitions (<Route>), and the Clickable Triggers (<Link>). Let's master the foundational components of React Router.
The <Routes> Container. In React Router v6, we use the <Routes> component as a container. Whenever the location changes, <Routes> looks through all its child routes to find the BEST match and renders that branch of the UI.
Upgrading: <Switch> to <Routes>. If you are maintaining an older React application (v5), you will see <Switch> instead of <Routes>. They serve a similar purpose, but <Routes> is much smarter. It uses a scoring algorithm to pick the most specific route, rather than just taking the first one that matches.
Which component acts as the smart container for all your individual route definitions in React Router v6?
- ā<Switch>
- ā<Routes>
Defining Individual Routes. Inside <Routes>, you place <Route> components. A Route acts as a mapping. It says, 'When the URL looks exactly like this path, I want you to render this specific element.'
element vs component. Another v5 vs v6 change: In v5, we used the component prop and passed the component reference (e.g., component={Home}). In v6, we use the element prop and pass a JSX element (e.g., element={<Home />}). This makes it much easier to pass props directly to the routed component!
The <Link> Component. To navigate between these routes, we use the <Link> component. It looks and acts like an HTML <a> tag, but it intercepts the click event. Instead of requesting a new document from the server, it uses the History API to change the URL instantly.
Why Not <a> Tags?. If you use <a href='/about'>, the browser will do a full page refresh. All your React state (variables, form data, Redux stores) will be completely wiped out and reset. NEVER use <a> tags for internal navigation within an SPA.
What prop does the <Link> component use to specify the destination URL?
- āhref
- āto
The <NavLink> Component. For Navigation Menus (like a sidebar or header), you often need to highlight the currently active page. React Router provides <NavLink>, a special version of <Link> that knows whether or not it is currently 'active'.
Active State Styling. You can pass a function to the className or style prop of a <NavLink>. React Router will call your function, passing an object with an isActive boolean. You use this to apply specific CSS when the link matches the URL.
Which component should you use for a navigation menu that needs to dynamically highlight the currently active page?
- ā<Link>
- ā<NavLink>
Absolute vs Relative Links. When defining paths in to (for Links) or path (for Routes), starting with a slash (/about) makes it an ABSOLUTE path from the root domain. Omit the slash (about) to make it RELATIVE to the current URL.
Layout Routes & Outlet. A powerful pattern in v6 is the Layout Route. You can define a parent route that wraps its children with a common UI (like a Navbar). The parent component uses an <Outlet> to indicate where the child routes should be injected.
Mastery Achieved. Foundation complete! You now know how to map URLs to components using <Routes> and <Route>, and create seamless, state-preserving navigation links using <Link> and <NavLink>.
Level Up š
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1Link Renders a Real Anchor Element
Even though `<Link>` intercepts clicks to avoid a full page reload, it still renders an actual `<a>` tag under the hood, which preserves native keyboard focus, screen reader link semantics, and middle-click/ctrl-click-to-open-in-new-tab behavior.
2Route Changes Should Move Focus to New Content
Because client-side navigation doesn't reload the page, the browser won't automatically reset focus the way a full page load would ā move focus to the new view's heading or main content after a route change so screen reader and keyboard users know navigation occurred.
SEO Implications
- 1
Client-Side Routing Still Needs Real, Crawlable URLs
Each `<Route path>` should correspond to a distinct, meaningful URL that a crawler can request directly and get relevant content for ā client-side routing doesn't change the fact that each page needs its own indexable URL.
- 2
Internal Links Should Use Link, Not JavaScript-Only Navigation
Rendering navigation as `<Link to="/about">` produces a real `<a href>` in the DOM that crawlers can follow and extract the destination URL from, unlike navigation triggered purely by a JavaScript `onClick` handler with no underlying `href`.
Best Practices
Always Use Link or NavLink for Internal Navigation
A plain `<a href>` triggers a full browser reload and wipes all in-memory React state; `<Link>` and `<NavLink>` update the URL via the History API while preserving the app's current state.
Reach for element, Not the Legacy component Prop
In React Router v6, `<Route element={<Home />}>` is the standard way to specify what renders for a path ā it accepts JSX directly, making it trivial to pass additional props to the routed component.
Frequent Bugs
Clicking an internal navigation link resets all component and Redux state.
The link was a plain `<a href="...">` instead of React Router's `<Link to="...">`. A native anchor tag causes a full page reload; replace it with `<Link>` to navigate without losing in-memory state.
Multiple Route elements seem to match the same URL, and the wrong component renders.
In a v6 app relying on order-dependent matching left over from a v5 mental model, remember that `<Routes>` uses a scoring algorithm to pick the most specific match regardless of order ā check that route `path` values are specific enough to disambiguate correctly.
Real-World Examples
Navbar Built with Routes and Link
An app defines `<Route path="/" element={<Home />} />` and `<Route path="/about" element={<About />} />` inside `<Routes>`, with a navbar using `<Link to="/about">About</Link>` so users can move between pages instantly without losing any in-memory state.
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>