Skip to content

React Tutorial Routing and Application Structure

Navigation in React Router: Link, NavLink and useNavigate

Lesson 106 of 156 3 min read By Deepak Paswan Updated Oct 10, 2026

Full-project lesson · needs Node.js, npm and real project files, so it does not run in the in-page playground.

There are four ways to move around a React Router app. Choose by what triggers the move.

ToolTriggered byUse for
<Link>The user clicks a linkNormal navigation
<NavLink>The user clicks a link; it knows if it is activeMenus and tabs
useNavigate()Code (after a form, a timer, a login)Programmatic navigation
<Navigate>RenderingRedirects
App.jsx
JSX
<Link to="/about">About us</Link>

It renders <a href="/about">, so it supports opening in a new tab, copying the address and keyboard use. Never wrap a <button> inside a link or vice versa.

Relative links. A to without a leading slash is relative to the current route: from /products, <Link to="42"> goes to /products/42, and <Link to=".."> goes up one level.

NavLink is a Link that knows whether it matches the current URL. It adds the class active and the attribute aria-current="page" automatically, which helps screen reader users. Style it with CSS (a.active { ... }) or with a function:

src/App.jsx
JSX
import { Routes, Route, NavLink, Navigate, useNavigate } from 'react-router'

function Home() {
  const navigate = useNavigate()
  return (
    <div>
      <h1>Home page</h1>
      <button onClick={() => navigate('/about')}>Go to About with a button</button>
    </div>
  )
}

function About() {
  const navigate = useNavigate()
  return (
    <div>
      <h1>About page</h1>
      <button onClick={() => navigate('/')}>Go home with a button</button>
    </div>
  )
}

const linkStyle = ({ isActive }) => ({
  fontWeight: isActive ? 700 : 400,
  textDecoration: isActive ? 'underline' : 'none',
})

function App() {
  return (
    <div>
      <nav style={{ display: 'flex', gap: 16 }}>
        <NavLink to="/" end style={linkStyle}>Home</NavLink>
        <NavLink to="/about" style={linkStyle}>About</NavLink>
      </nav>

      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/old-about" element={<Navigate to="/about" replace />} />
      </Routes>
    </div>
  )
}

export default App

This project was built with Vite and tested in a browser: the active link has aria-current="page" and bold text, the buttons navigate, and /old-about redirects to /about.

Details:

  • end on the Home link stops it from being “active” for every path that starts with / (all of them). Use end on links to / and on parent links when you want an exact match.
  • style, className and children all accept a function that receives { isActive, isPending }.
  • aria-current="page" is added for you; do not remove it.

useNavigate: navigate from code

Use it after an event that is not a plain link click: a successful login, a form submission, a “Back” button:

App.jsx
JSX
const navigate = useNavigate()

async function handleSubmit(e) {
  e.preventDefault()
  await saveOrder()
  navigate('/thank-you')            // go to a new page
}

navigate(-1)                         // like the browser Back button
navigate('/login', { replace: true }) // replace the current history entry

replace: true swaps the current entry instead of adding one, so the user cannot press Back to a page that should be skipped, such as a login form after logging in.

You can also pass state that does not appear in the URL: navigate('/next', { state: { fromSearch: true } }), read with useLocation().state. It is lost on refresh in some cases, so do not rely on it for important data.

<Navigate to="/about" replace /> redirects as soon as it renders. Use it for old URLs (as above) or for protected pages:

App.jsx
JSX
function RequireAuth({ user, children }) {
  if (!user) return <Navigate to="/login" replace />
  return children
}

(Real authentication also needs server checks; see API Security Fundamentals.)

If a click only goes to another page, use Link, not a button with navigate. A link works with middle-click, “open in new tab”, keyboard and assistive technology. Reserve navigate() for navigation that follows an action.

Active section highlighting

By default, NavLink to="/products" is active for /products and also for /products/42, because the second path is “inside” the first. That is usually what you want for a menu. Use end if you do not.

Scroll restoration and focus

When the route changes, the browser does not scroll to the top or move focus by itself in a single-page app. In data mode, add <ScrollRestoration /> to your layout. For keyboard and screen reader users, move focus to the new page’s main heading after navigation; see Accessible Focus States and Accessibility in React.

Key points

  • Link for clicks, NavLink for menus (adds active and aria-current), useNavigate for navigation from code, Navigate for redirects.
  • Use end so / links are not always active.
  • Prefer real links; manage scroll and focus after navigation.