Client-Side Routing
By Syncfusion®, Inc. · Last updated
Routing with React Router: BrowserRouter, Routes and Route, Link and NavLink, useNavigate, route and query parameters, nested and index routes, layouts and a Not Found page.
Introduction to Routing
Routing means showing a different page for each web address (URL). For example, /books shows the list of books, and /about shows the About page.
In a React app, routing happens in the browser. This is called client-side routing. When you click a link, React changes the address and swaps the component on the screen. The page does not reload.
Real-World Example
A bookshop app has the URLs /, /books and /books/42. React Router reads the URL and shows Home, BookList or BookDetails.
A user clicks a <Link to="/books/42">. The router changes the URL and shows the details of book 42 without a page reload. The user can bookmark this URL or share it.
Client-side routing: the address changes, and React shows a different component, without reloading the page
bookcorner.com/
bookcorner.com/books
bookcorner.com/about
<HomePage />
<BooksPage />
<AboutPage />
One page in the browser. Only the part that matches the address is swapped.
A React app is one HTML page. The router reads the URL and decides which component to show.
Setting Up React Router
React does not have routing built in. The most used routing library is React Router. Its package for websites is called react-router-dom.
Install it in your project with one command:
npm install react-router-dom
Then you import the parts you need from "react-router-dom", such as BrowserRouter, Routes, Route and Link. This lesson uses React Router version 6.
The code boxes on this page already have React Router installed. Each box shows a small address bar at the top of the preview, with Back and Forward buttons, so you can see the URL change.
BrowserRouter
BrowserRouter is the component that turns routing on. You wrap your whole app in it, once, usually in main.tsx or at the top of App.
import { BrowserRouter } from "react-router-dom";
createRoot(document.getElementById("root")!).render(
<BrowserRouter>
<App />
</BrowserRouter>
);
BrowserRouter keeps the app in step with the browser's address bar. It also makes the browser's Back and Forward buttons work.
All other router parts, such as Routes, Link and useNavigate, only work inside BrowserRouter.
The code boxes on this page cannot change your real address bar. So inside them, BrowserRouter keeps the address in memory, and draws a small address bar at the top of the preview. Your code is the same as in a real app.
Routes and Route Components
You list your pages with two components:
<Routes>— a container that holds all your routes. It shows only the one route that matches the URL.<Route>— one page.pathis the address, andelementis the component to show.
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/books" element={<BooksPage />} />
<Route path="/about" element={<AboutPage />} />
</Routes>
The URL is compared with each Route path. The matching Route's element is shown
/books the URL now
<Routes>
path="/"
path="/books"
path="/about"
<BooksPage /> shown
Routes looks for the Route whose path matches the URL, and shows its element.
Navigation with Link
<Link> makes a clickable link to another route. Use to for the address.
<Link to="/books">Books</Link>
Do not use a normal <a href="/books"> inside a React app. A normal link reloads the whole page, so all your state is lost. Link changes the page without reloading.
Click the links. The address bar at the top changes, and only the heading below the menu changes. The menu stays, because it is outside <Routes>.
Now press the ← Back button in the address bar. You go back to the page before, just like in a real browser.
NavLink
NavLink is a special Link that knows when its page is open. It gives itself the class active on the current page. You can use that class to highlight the menu item.
Click each menu item. The blue one is always the page you are on.
Look at end on the Home link. Without it, / would count as active on every page, because every address starts with /. end means: active only when the address is exactly /.
useNavigate Hook
Sometimes you want to change the page from code, not from a link. For example, go to a "Thank you" page after an order is placed.
useNavigate gives you a function, usually called navigate. Call it with an address.
const navigate = useNavigate();
navigate("/thank-you"); // go to this page
navigate(-1); // go back one page
Click Place order. The code runs first (the console shows a message), and then navigate opens the thank-you page.
Use Link when the user clicks to go somewhere. Use navigate when your code decides to go somewhere, such as after a form is sent.
Route Parameters
A route parameter is a changing part of the address, such as the id of a book: /books/1, /books/2, /books/3.
You write one route with a : before the changing part. Then you read it with the useParams hook.
Route parameter: the path /books/:id matches /books/42, and useParams gives id = 42
/books/42 the URL
/books/:id the Route path
useParams() { id: "42" }
The :id part of the path catches any value, and useParams gives it to you.
Click a book. The address becomes /books/2, for example. BookDetails reads id with useParams, and finds the book with that id.
Look at this line:
const { id } = useParams();
The name id matches :id in the route path. A parameter is always text, so the ids in books.ts are text too: "2", not 2.
Query Parameters
Query parameters are extra settings at the end of the address, after a ?. For example: /search?q=habits&sort=price.
They are used for things like search words, filters and sorting. They do not change which route matches. You read and change them with useSearchParams.
Query parameters: the part after ? holds key=value pairs, read with useSearchParams /search?q=habits&sort=price path q = "habits" sort = "price" ? starts the list · & joins two pairs
Query parameters are optional settings after the ?. They do not change which Route matches.
Type in in the box. The address becomes /?q=in, and the list shows only matching books. Because the search is in the address, a user can copy the link and share the same search.
searchParams.get("q")reads the value ofq. It givesnullif there is noq, so?? ""uses an empty text instead.setSearchParams({ q: "..." })changes the query part of the address.
Nested Routes
A nested route is a route inside another route. The child's path is added to the parent's path.
<Route path="/account" element={<AccountPage />}>
<Route path="orders" element={<Orders />} /> {/* /account/orders */}
<Route path="profile" element={<Profile />} /> {/* /account/profile */}
</Route>
The parent component decides where the child appears, with <Outlet />. Outlet is a placeholder. React Router puts the matching child component there.
Index Routes
An index route is the child that shows when the address is exactly the parent's path. It has index instead of a path.
<Route path="/account" element={<AccountPage />}>
<Route index element={<AccountHome />} /> {/* /account */}
<Route path="orders" element={<Orders />} /> {/* /account/orders */}
</Route>
Without an index route, the Outlet would be empty at /account.
Route Layouts
A layout route is a parent route that holds the parts every page shares, such as the header, menu and footer. The pages are its children, shown in the Outlet.
A layout route keeps the header and footer. The Outlet is the hole where the child page appears
Layout (stays the same)
Header · Home · Books · About
<Outlet />
Home page
Books page
About page
Footer
The child page changes inside the Outlet. The header and footer are not drawn again.
Click through the menu. The header and footer never change. Only the middle part changes:
- At
/, the index route of the layout shows "Home". - At
/account, the index route ofAccountshows "Hello, Asha". - At
/account/orders, theordersroute shows insideAccount, which shows insideLayout.
Notice that child paths have no / at the start: path="account", not path="/account". A child path is added to its parent's path.
Not Found Page
When the address matches no route, React shows nothing. To show a friendly message instead, add a route with path="*". The * matches any address that no other route matched.
Click Old offers link. No route has that path, so the * route shows the "Page not found" message.
Common mistakes
| Mistake | What you see | Fix |
|---|---|---|
Using Link or useNavigate outside BrowserRouter | Error: useHref() may be used only in the context of a <Router> | Wrap the app in <BrowserRouter> |
Using <a href> for pages inside the app | The page reloads and the state is lost | Use <Link to> |
Forgetting <Outlet /> in a parent route | The child page never shows | Add <Outlet /> where the child should appear |
Starting a child path with / | The child does not match as expected | Write path="orders", not path="/orders" |
Forgetting end on the Home NavLink | Home is always highlighted | Add end to the / link |
| Comparing a route parameter with a number | The item is not found | Parameters are text: compare with "2", or use Number(id) |
No * route | Unknown addresses show an empty page | Add <Route path="*" element={<NotFound />} /> |
Check Yourself
Exercises
What to Remember
- Wrap the app in
BrowserRouter, list pages withRoutesandRoute, and move between them withLink,NavLinkoruseNavigate. - Read
/books/:idwithuseParams, and?q=...withuseSearchParams. - Use a layout route with
<Outlet />for shared parts,indexfor the default child, andpath="*"for a Not Found page.
Next: User Access Control