How to Create Route in React JS?

How to Create Routes in React JS – React Router v6 Guide (2026)

Table of Contents

Quick answer

Create routes in React using React Router v6 in 4 steps:

  1. Install React Router: npm install react-router-dom
  2. Wrap your app with <BrowserRouter> in main.jsx
  3. Define routes with <Routes> and <Route element={} path="" />
  4. Add navigation with <Link> and <Outlet> for nested pages

That’s it. You now have a multi-page React app with seamless navigation.

What is routing in React?

Routing is the ability to navigate between different pages or views in your React application without reloading the entire page. Instead of refreshing the browser, JavaScript changes what’s displayed based on the URL.

Example: When a user clicks “About”, the URL changes from localhost:5173/ to localhost:5173/about, and React renders the About component instead of the Home component.

This creates the illusion of multiple pages, but it’s all one single-page application (SPA). No server round-trips, no full page refresh. This is why modern React apps feel fast and responsive.

Why routing matters

Without routing, your React app is limited to a single page. With routing, you can build:

  • Multi-page websites (Home, About, Contact, Blog)
  • E-commerce stores (Products, Product detail, Cart, Checkout)
  • Dashboards (Overview, Analytics, Settings, Users)
  • Admin panels with complex navigation hierarchies

React Router is the de facto standard for routing in React. It’s maintained by Remix (the team behind modern full-stack React), and it’s what the React + VS Code setup guide points to when you’re ready for navigation.

Prerequisites

  • A React app running with Vite (follow the Vite setup guide if you haven’t already)
  • Understanding of npm and packages (we’ll install react-router-dom)
  • VS Code or any text editor
  • ~15 minutes

Step 1: Install React Router v6

In your project directory, run:

bash

npm install react-router-dom

This downloads React Router v6 (the latest, modern version released in 2022) and adds it to your package.json.

Output:

added 3 packages in 2s

That’s it. React Router is now available in your project.

Step 2: Set up BrowserRouter in your app

Open your src/main.jsx file (or index.jsx depending on your Vite template).

BEFORE:

jsx

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'

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

AFTER: Wrap your App with BrowserRouter

jsx

import React from 'react'
import ReactDOM from 'react-dom/client'
import { BrowserRouter } from 'react-router-dom'
import App from './App.jsx'

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

What BrowserRouter does:

  • Monitors URL changes
  • Tells React Router which component to render based on the current URL
  • Enables the <Link> component to work without full page reloads

Think of it as the engine that powers all routing in your app. Everything else (routes, links, navigation) depends on this wrapper.

Step 3: Create your first routes

Now, in your src/App.jsx, define which pages exist and what components should render for each.

Basic example:

jsx

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

function App() {
  return (
    <Routes>
      <Route path="/" element={<Home />} />
      <Route path="/about" element={<About />} />
      <Route path="/contact" element={<Contact />} />
    </Routes>
  )
}

export default App

What’s happening:

  • <Routes> — Container for all your routes
  • <Route path="" element={} /> — Defines one route (React Router v6 syntax)
    • path="/" — URL path
    • element={<Home />} — Component to render (v6 uses element, not component)

When a user visits /about, React Router renders the About component at that URL.

Step 4: Add navigation with Links

Users need a way to navigate between pages. Use the <Link> component instead of <a> tags.

Create a src/components/Navigation.jsx:

jsx

import { Link } from 'react-router-dom'

function Navigation() {
  return (
    <nav style={{ padding: '1rem', backgroundColor: '#f0f0f0' }}>
      <ul style={{ display: 'flex', listStyle: 'none', gap: '2rem' }}>
        <li><Link to="/">Home</Link></li>
        <li><Link to="/about">About</Link></li>
        <li><Link to="/contact">Contact</Link></li>
      </ul>
    </nav>
  )
}

export default Navigation

Now import and use Navigation in your App:

jsx

import { Routes, Route } from 'react-router-dom'
import Navigation from './components/Navigation'
import Home from './pages/Home'
import About from './pages/About'
import Contact from './pages/Contact'

function App() {
  return (
    <>
      <Navigation />
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/contact" element={<Contact />} />
      </Routes>
    </>
  )
}

export default App

Why <Link> instead of <a>:

  • <a href="/about"> → Full page reload (slow)
  • <Link to="/about"> → Only re-renders the component (fast, no refresh)

Advanced routing patterns

1. Dynamic routes with parameters

Sometimes you need routes that change based on data. For example, a blog where each post has a unique ID.

Route definition:

jsx

<Route path="/blog/:id" element={<BlogPost />} />

Accessing the parameter in your component:

jsx

import { useParams } from 'react-router-dom'

function BlogPost() {
  const { id } = useParams()
  
  return (
    <div>
      <h1>Blog Post #{id}</h1>
      {/* Fetch post data using the id */}
    </div>
  )
}

Now when a user visits /blog/42, the id parameter is 42.

Real example:

jsx

// Route: /users/:userId/posts/:postId
const { userId, postId } = useParams()
// User visits: /users/15/posts/87
// userId = "15", postId = "87"

2. Nested routes

Complex apps often have routes within routes. For example:

/dashboard
├─ /dashboard/overview
├─ /dashboard/analytics
└─ /dashboard/settings

Define nested routes:

jsx

<Route path="/dashboard" element={<DashboardLayout />}>
  <Route path="overview" element={<Overview />} />
  <Route path="analytics" element={<Analytics />} />
  <Route path="settings" element={<Settings />} />
</Route>

In DashboardLayout.jsx, use <Outlet> to render child routes:

jsx

import { Link, Outlet } from 'react-router-dom'

function DashboardLayout() {
  return (
    <div style={{ display: 'flex' }}>
      <nav style={{ width: '200px', borderRight: '1px solid #ccc' }}>
        <ul style={{ listStyle: 'none', padding: '1rem' }}>
          <li><Link to="/dashboard/overview">Overview</Link></li>
          <li><Link to="/dashboard/analytics">Analytics</Link></li>
          <li><Link to="/dashboard/settings">Settings</Link></li>
        </ul>
      </nav>
      <main style={{ flex: 1, padding: '1rem' }}>
        <Outlet /> {/* Child route renders here */}
      </main>
    </div>
  )
}

<Outlet> is a placeholder where child routes render. Without it, child routes won’t display.

3. Handling 404 pages

What if a user visits a URL that doesn’t exist? Create a catch-all route:

jsx

<Routes>
  <Route path="/" element={<Home />} />
  <Route path="/about" element={<About />} />
  <Route path="/contact" element={<Contact />} />
  <Route path="*" element={<NotFound />} /> {/* Catch all */}
</Routes>

The path="*" route matches any URL that didn’t match above. Put it last.

NotFound.jsx:

jsx

import { Link } from 'react-router-dom'

function NotFound() {
  return (
    <div style={{ textAlign: 'center', padding: '2rem' }}>
      <h1>404 - Page Not Found</h1>
      <p>The page you're looking for doesn't exist.</p>
      <Link to="/">Go back home</Link>
    </div>
  )
}

4. Programmatic navigation with useNavigate

Sometimes you need to navigate after an action (form submission, login, etc.). Use the useNavigate hook:

jsx

import { useNavigate } from 'react-router-dom'

function LoginForm() {
  const navigate = useNavigate()
  
  const handleSubmit = (e) => {
    e.preventDefault()
    // Validate login...
    // If successful:
    navigate('/dashboard')
  }
  
  return (
    <form onSubmit={handleSubmit}>
      <input type="email" placeholder="Email" />
      <input type="password" placeholder="Password" />
      <button type="submit">Login</button>
    </form>
  )
}

After login, the user is redirected to /dashboard programmatically.

Real-world example: E-commerce app

Here’s a complete routing setup for a small e-commerce app:

jsx

import { Routes, Route } from 'react-router-dom'
import Navigation from './components/Navigation'
import Home from './pages/Home'
import Products from './pages/Products'
import ProductDetail from './pages/ProductDetail'
import Cart from './pages/Cart'
import Checkout from './pages/Checkout'
import NotFound from './pages/NotFound'

function App() {
  return (
    <>
      <Navigation />
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/products" element={<Products />} />
        <Route path="/products/:id" element={<ProductDetail />} />
        <Route path="/cart" element={<Cart />} />
        <Route path="/checkout" element={<Checkout />} />
        <Route path="*" element={<NotFound />} />
      </Routes>
    </>
  )
}

export default App

Flow:

  1. User lands on / (Home)
  2. Clicks “Products” → /products (all products)
  3. Clicks a product → /products/42 (ProductDetail gets id=42)
  4. Adds to cart → /cart
  5. Clicks checkout → /checkout
  6. Visits invalid URL → /products/not-found → 404 page

React Router v6 vs. v5: Key differences

If you’re migrating from React Router v5, here’s what changed:

Featurev5v6
Component prop<Route component={Home} /><Route element={<Home />} />
Render function<Route render={() => ...} /><Route element={<Home />} />
Exact matching<Route exact path="/" />Path matching is exact by default
Switch component<Switch><Routes>
Navigate component<Redirect /><Navigate />
HooksLimiteduseParams, useNavigate, useLocation, useSearchParams
Nested routesFlat structureNative nested <Route> support
Relative pathsNot supportedSupported (cleaner, less repetition)

v6 example (cleaner):

<Route path="/dashboard" element={<DashboardLayout />}>
  <Route path="overview" element={<Overview />} /> {/* Relative */}
  <Route path="analytics" element={<Analytics />} /> {/* Relative */}
</Route>

v5 equivalent (verbose):

<Route path="/dashboard" component={DashboardLayout} />
<Route path="/dashboard/overview" component={Overview} />
<Route path="/dashboard/analytics" component={Analytics} />

Common routing patterns and mistakes

✅ Correct: Use relative paths in nested routes

<Route path="/dashboard" element={<Dashboard />}>
  <Route path="analytics" element={<Analytics />} /> {/* Correct */}
</Route>

❌ Wrong: Repeating full paths

<Route path="/dashboard" element={<Dashboard />}>
  <Route path="/dashboard/analytics" element={<Analytics />} /> {/* Redundant */}
</Route>

✅ Correct: Use useNavigate for conditional navigation

const navigate = useNavigate()
if (isLoggedIn) {
  navigate('/dashboard')
} else {
  navigate('/login')
}

❌ Wrong: Using window.location for SPA navigation

window.location.href = '/dashboard' // Full page reload (breaks SPA)

✅ Correct: Link components don’t reload

<Link to="/about">About</Link> {/* Client-side, instant */}

❌ Wrong: Using <a> tags for internal navigation

<a href="/about">About</a> {/* Full page reload */}

Comparison: React Router vs. alternatives

LibraryLearning curvePopularityPerformanceBest for
React Router v6ModerateVery high (90%+ of projects)ExcellentMost React apps
TanStack RouterModerate-highGrowingExcellent (Vite-native)Modern, type-safe projects
Next.js (file-based)EasyVery highExcellentFull-stack React apps
RemixModerateGrowingExcellentFull-stack, server-heavy
WouterEasyLow (alternative)GoodSmall, lightweight apps

For this guide: Use React Router v6. It’s the standard, has the best documentation, and integrates seamlessly with your Vite setup.

FAQ

Q: What’s the difference between <Link> and <a>?

A: <Link> prevents full page reloads, keeping your SPA fast. <a> reloads the entire page. For internal navigation, always use <Link>.

Q: Do I need nested routes?

A: No, but they keep your code organized. For apps with 3–5 pages, flat routes are fine. For dashboards or complex apps, nested routes reduce repetition and improve maintainability.

Q: How do I pass data between routes?

A: Use URL parameters (/users/:id), query strings (/search?q=hello), or state management like Context or Redux. Avoid passing data through <Link state={} /> — it’s lost on refresh.

Q: Can I have multiple <Routes> in my app?

A: Yes. You can have multiple <Routes> blocks. The first matching route wins. Useful for layout-based routing: one <Routes> in the main layout, others in nested components.

Q: How do I handle protected routes (login)?

A: Create a <ProtectedRoute> wrapper that checks authentication before rendering:

jsx

function ProtectedRoute({ element }) {
  const isAuthenticated = !!localStorage.getItem('auth_token')
  return isAuthenticated ? element : <Navigate to="/login" />
}

// Usage:
<Route path="/dashboard" element={<ProtectedRoute element={<Dashboard />} />} />

Q: What’s the difference between useParams and useSearchParams?

A:

  • useParams — Dynamic route parameters: /users/:iduseParams().id
  • useSearchParams — Query strings: /search?q=coffeeuseSearchParams().get('q')

Q: How do I update the page title for each route?

A: Use the useEffect hook in each component:

useEffect(() => {
  document.title = 'Products | My App'
}, [])

Or use a library like react-helmet.

Q: Can I have routes with optional parameters?

A: Yes, using regex:

<Route path="/products/:id?" element={<Products />} />
// Matches both /products and /products/42

Q: How do I handle deep linking (sharing URLs)?

A: React Router handles this automatically. If you share /products/42, the user lands on that specific product. No special setup needed.

Q: What if I need to validate route parameters?

A: Validate in your component:

function ProductDetail() {
  const { id } = useParams()
  
  if (!id || isNaN(id)) {
    return <Navigate to="/404" />
  }
  
  return <div>Product {id}</div>
}

Troubleshooting routing issues

“Cannot match any routes”

Problem: You visit /about, but the page shows blank.

Causes & fixes:

  1. Route path doesn’t match. Check spelling: /about vs /About
  2. Missing <BrowserRouter> wrapper in main.jsx
  3. Using <a href=""> instead of <Link to="">

Fix: Verify route paths are exact.

“useNavigate is not a function”

Problem: You used useNavigate() outside a component or before BrowserRouter.

Fix: Make sure component is inside <BrowserRouter>:

<BrowserRouter>
  <App /> {/* useNavigate works here */}
</BrowserRouter>

“useParams returns undefined”

Problem: You defined /products/:id, but useParams().id is undefined.

Causes:

  1. Route path is /products (no :id). Check spelling.
  2. User visited wrong URL: /products/ instead of /products/42

Fix: Verify URL has the parameter.

“Links navigate but page doesn’t update”

Problem: URL changes, but component doesn’t re-render.

Cause: Component doesn’t depend on params/location.

Fix: Use useParams() or useLocation() inside component:

import { useParams, useLocation } from 'react-router-dom'

function MyComponent() {
  const { id } = useParams() // Now component re-renders on param change
  // ...
}

Next steps

You now know how to create routes and navigate between pages. Ready to level up?

Go back to the React + Vite setup guide and follow “What to build next” to:

  • Render lists with React (complement your routing)
  • Add forms and handle submissions
  • Fetch data from APIs
  • Style your routed pages

You’ll also want to understand how npm manages packages — React Router comes from npm, and as your app grows, you’ll install more routing packages.

Once you master routing, debugging with React DevTools becomes much more powerful. You can inspect route state, props, and see component re-renders as you navigate.

Conclusion

Routing is the difference between a single-page app and a multi-page experience. With React Router v6, creating routes is straightforward: install, wrap with BrowserRouter, define routes, add links, and navigate.

The key is remembering: <Link> for user-clickable navigation, useNavigate() for programmatic navigation, useParams() for accessing route data, and <Outlet> for nested route rendering.

Master these four concepts, and you can build any routing structure your app needs.

Last updated: January 2026. Information current as of React Router v6.20+, React 19, Node 20 LTS.

Picture of Priyanshu Pathak

Priyanshu Pathak

Priyanshu Pathak is a Senior Developer at Sourcebae. He works across the stack to build fast, reliable features that make hiring simple. From APIs and integrations to performance and security, Priyanshu keeps our products clean, scalable, and easy to maintain.

Table of Contents

Hire top 1% global talent now

Related blogs

Quick answer npm (Node Package Manager) is a package manager for JavaScript that manages all the libraries and tools your

Quick answer Install React JS in VS Code in 10 minutes: Your React dev environment is live and hot-reloading. Full

Quick Answer React is primarily a front-end technology. It is a JavaScript library designed for building user interfaces that run

Quick Answer React is a library specifically, a JavaScript library for building user interfaces. This is not a matter of