Link

<Link> est un composant React qui étend l'élément HTML <a> pour fournir un préchargement et une navigation côté client entre les routes. C'est le moyen principal de naviguer entre les routes dans Next.js.

Utilisation de base :

import Link from 'next/link'

export default function Home() {
  return <Link href="/dashboard">Dashboard</Link>
}

Référence

Les propriétés suivantes peuvent être passées au composant <Link> :

PropriétéExempleTypeRequis
hrefhref="/dashboard"String ou ObjectOui
replacereplace={false}Boolean-
scrollscroll={false}Boolean-
prefetchprefetch={false}Boolean-
legacyBehaviorlegacyBehavior={true}Boolean-
passHrefpassHref={true}Boolean-
shallowshallow={false}Boolean-
localelocale="fr"String ou Boolean-
onNavigateonNavigate={(e) => {}}Function-

Bon à savoir : Les attributs de balise <a> comme className ou target="_blank" peuvent être ajoutés à <Link> comme propriétés et seront transmis à l'élément <a> sous-jacent.

href (requis)

Le chemin ou l'URL vers lequel naviguer.

import Link from 'next/link'

// Naviguer vers /about?name=test
export default function Home() {
  return (
    <Link
      href={{
        pathname: '/about',
        query: { name: 'test' },
      }}
    >
      About
    </Link>
  )
}

replace

Par défaut false. Lorsque true, next/link remplacera l'état actuel de l'historique au lieu d'ajouter une nouvelle URL dans la pile d'historique du navigateur.

import Link from 'next/link'

export default function Home() {
  return (
    <Link href="/dashboard" replace>
      Dashboard
    </Link>
  )
}

scroll

Par défaut true. Le comportement de défilement par défaut de <Link> dans Next.js est de maintenir la position de défilement, similaire à la façon dont les navigateurs gèrent la navigation avant et arrière. Lorsque vous naviguez vers une nouvelle Page, la position de défilement restera la même tant que la Page est visible dans la fenêtre d'affichage. Cependant, si la Page n'est pas visible dans la fenêtre d'affichage, Next.js fera défiler jusqu'au premier élément de la Page.

Lorsque scroll = {false}, Next.js ne tentera pas de faire défiler jusqu'au premier élément de la Page.

Bon à savoir : Next.js vérifie si scroll: false avant de gérer le comportement de défilement. Si le défilement est activé, il identifie le nœud DOM pertinent pour la navigation et inspecte chaque élément de premier niveau. Tous les éléments non défilables et ceux sans HTML rendu sont contournés, cela inclut les éléments positionnés en sticky ou fixed, et les éléments non visibles tels que ceux calculés avec getBoundingClientRect. Next.js continue ensuite à travers les éléments frères jusqu'à identifier un élément défilable visible dans la fenêtre d'affichage.

import Link from 'next/link'

export default function Home() {
  return (
    <Link href="/dashboard" scroll={false}>
      Dashboard
    </Link>
  )
}

prefetch

Le préchargement se produit lorsqu'un composant <Link /> entre dans la fenêtre d'affichage de l'utilisateur (initialement ou par défilement). Next.js précharge et charge la route liée (désignée par href) et les données en arrière-plan pour améliorer les performances des navigations côté client. Le préchargement n'est activé qu'en production.

Les valeurs suivantes peuvent être passées à la propriété prefetch :

  • true (par défaut) : La route complète et ses données seront préchargées.
  • false : Le préchargement ne se produira pas lors de l'entrée dans la fenêtre d'affichage, mais se produira lors du survol. Si vous souhaitez également supprimer complètement le préchargement lors du survol, envisagez d'utiliser une balise <a> ou d'adopter progressivement le routeur App, qui permet également de désactiver le préchargement lors du survol.
import Link from 'next/link'

export default function Home() {
  return (
    <Link href="/dashboard" prefetch={false}>
      Dashboard
    </Link>
  )
}

legacyBehavior

Avertissement : La propriété legacyBehavior sera supprimée dans Next.js v16. Pour adopter le nouveau comportement de <Link>, supprimez toutes les balises <a> utilisées comme enfants de <Link>. Un codemod est disponible pour vous aider à mettre à niveau automatiquement votre codebase.

Depuis la version 13, un élément <a> n'est plus requis comme enfant du composant <Link>. Si vous avez encore besoin de l'ancien comportement pour des raisons de compatibilité, vous pouvez ajouter la propriété legacyBehavior.

Bon à savoir : lorsque legacyBehavior n'est pas défini sur true, toutes les propriétés de balise anchor peuvent également être passées à next/link, telles que className, onClick, etc.

passHref

Force Link à transmettre la propriété href à son enfant. Par défaut false. Voir l'exemple passer un composant fonctionnel pour plus d'informations.

shallow

Met à jour le chemin de la page actuelle sans relancer getStaticProps, getServerSideProps ou getInitialProps. Par défaut false.

import Link from 'next/link'

export default function Home() {
  return (
    <Link href="/dashboard" shallow={false}>
      Dashboard
    </Link>
  )
}

locale

La locale active est automatiquement préfixée. locale permet de fournir une locale différente. Lorsque false, href doit inclure la locale car le comportement par défaut est désactivé.

import Link from 'next/link'

export default function Home() {
  return (
    <>
      {/* Comportement par défaut : la locale est préfixée */}
      <Link href="/dashboard">Dashboard (avec locale)</Link>

      {/* Désactiver le préfixage de la locale */}
      <Link href="/dashboard" locale={false}>
        Dashboard (sans locale)
      </Link>

      {/* Spécifier une locale différente */}
      <Link href="/dashboard" locale="fr">
        Dashboard (Français)
      </Link>
    </>
  )
}

onNavigate

Un gestionnaire d'événements appelé lors de la navigation côté client. Le gestionnaire reçoit un objet événement qui inclut une méthode preventDefault(), vous permettant d'annuler la navigation si nécessaire.

import Link from 'next/link'

export default function Page() {
  return (
    <Link
      href="/dashboard"
      onNavigate={(e) => {
        // Ne s'exécute que pendant la navigation SPA
        console.log('Navigation en cours...')

        // Optionnellement empêcher la navigation
        // e.preventDefault()
      }}
    >
      Dashboard
    </Link>
  )
}

Bon à savoir : Bien que onClick et onNavigate puissent sembler similaires, ils servent des objectifs différents. onClick s'exécute pour tous les événements de clic, tandis que onNavigate ne s'exécute que pendant la navigation côté client. Quelques différences clés :

  • Lors de l'utilisation de touches de modification (Ctrl/Cmd + Clic), onClick s'exécute mais pas onNavigate car Next.js empêche la navigation par défaut pour les nouveaux onglets.
  • Les URL externes ne déclencheront pas onNavigate car elle est uniquement pour les navigations côté client et de même origine.
  • Les liens avec l'attribut download fonctionneront avec onClick mais pas avec onNavigate car le navigateur traitera l'URL liée comme un téléchargement.

Exemples

Les exemples suivants démontrent comment utiliser le composant <Link> dans différents scénarios.

Lien vers des segments de route dynamiques

Pour les segments de route dynamiques, il peut être pratique d'utiliser des littéraux de modèle pour créer le chemin du lien.

Par exemple, vous pouvez générer une liste de liens vers la route dynamique pages/blog/[slug].js

import Link from 'next/link'

function Posts({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>
          <Link href={`/blog/${post.slug}`}>{post.title}</Link>
        </li>
      ))}
    </ul>
  )
}

Si l'enfant est un composant personnalisé qui englobe une balise <a>

Si l'enfant de Link est un composant personnalisé qui englobe une balise <a>, vous devez ajouter passHref à Link. Ceci est nécessaire si vous utilisez des bibliothèques comme styled-components. Sans cela, la balise <a> n'aura pas l'attribut href, ce qui nuit à l'accessibilité de votre site et peut affecter le SEO. Si vous utilisez ESLint, il existe une règle intégrée next/link-passhref pour garantir une utilisation correcte de passHref.

import Link from 'next/link'
import styled from 'styled-components'

// Ceci crée un composant personnalisé qui englobe une balise <a>
const RedLink = styled.a`
  color: red;
`

function NavLink({ href, name }) {
  return (
    <Link href={href} passHref legacyBehavior>
      <RedLink>{name}</RedLink>
    </Link>
  )
}

export default NavLink
  • Si vous utilisez la fonctionnalité JSX pragma d'emotion (@jsx jsx), vous devez utiliser passHref même si vous utilisez directement une balise <a>.
  • Le composant doit prendre en charge la propriété onClick pour déclencher correctement la navigation.

Imbrication d'un composant fonctionnel

Si l'enfant de Link est un composant fonctionnel, en plus d'utiliser passHref et legacyBehavior, vous devez encapsuler le composant dans React.forwardRef :

import Link from 'next/link'
import React from 'react'

// Définir le type des props pour MyButton
interface MyButtonProps {
  onClick?: React.MouseEventHandler<HTMLAnchorElement>
  href?: string
}

// Utiliser React.ForwardRefRenderFunction pour typer correctement la ref transmise
const MyButton: React.ForwardRefRenderFunction<
  HTMLAnchorElement,
  MyButtonProps
> = ({ onClick, href }, ref) => {
  return (
    <a href={href} onClick={onClick} ref={ref}>
      Cliquez ici
    </a>
  )
}

// Utiliser React.forwardRef pour encapsuler le composant
const ForwardedMyButton = React.forwardRef(MyButton)

export default function Home() {
  return (
    <Link href="/about" passHref legacyBehavior>
      <ForwardedMyButton />
    </Link>
  )
}

Passage d'un objet URL

Link peut également recevoir un objet URL et le formatera automatiquement pour créer la chaîne d'URL :

import Link from 'next/link'

function Home() {
  return (
    <ul>
      <li>
        <Link
          href={{
            pathname: '/about',
            query: { name: 'test' },
          }}
        >
          À propos
        </Link>
      </li>
      <li>
        <Link
          href={{
            pathname: '/blog/[slug]',
            query: { slug: 'my-post' },
          }}
        >
          Article de blog
        </Link>
      </li>
    </ul>
  )
}

export default Home

L'exemple ci-dessus contient un lien vers :

  • Une route prédéfinie : /about?name=test
  • Une route dynamique : /blog/my-post

Vous pouvez utiliser toutes les propriétés définies dans la documentation du module URL de Node.js.

Remplacer l'URL au lieu de pousser

Le comportement par défaut du composant Link est de pousser une nouvelle URL dans la pile history. Vous pouvez utiliser la prop replace pour éviter d'ajouter une nouvelle entrée, comme dans l'exemple suivant :

import Link from 'next/link'

export default function Home() {
  return (
    <Link href="/about" replace>
      À propos
    </Link>
  )
}
import Link from 'next/link'

export default function Home() {
  return (
    <Link href="/about" replace>
      À propos
    </Link>
  )
}

Désactiver le défilement vers le haut de la page

Le comportement par défaut de Link est de défiler vers le haut de la page. Lorsqu'un hachage est défini, il défiera vers l'id spécifique, comme une balise <a> normale. Pour empêcher le défilement vers le haut / le hachage, vous pouvez ajouter scroll={false} à Link :

import Link from 'next/link'

export default function Home() {
  return (
    <Link href="/#hashid" scroll={false}>
      Désactive le défilement vers le haut
    </Link>
  )
}

Préchargement des liens dans le Middleware

Il est courant d'utiliser le Middleware pour l'authentification ou d'autres fonctionnalités impliquant la réécriture de l'utilisateur vers une page différente. Pour que le composant <Link /> précharge correctement les liens avec des réécritures via le Middleware, vous devez indiquer à Next.js à la fois l'URL à afficher et l'URL à précharger. Cela est nécessaire pour éviter des requêtes inutiles vers le middleware afin de connaître la route correcte à précharger.

Par exemple, si vous souhaitez servir une route /dashboard avec des vues authentifiées et visiteurs, vous pouvez ajouter ceci dans votre Middleware pour rediriger l'utilisateur vers la bonne page :

import { NextResponse } from 'next/server'

export function middleware(request: Request) {
  const nextUrl = request.nextUrl
  if (nextUrl.pathname === '/dashboard') {
    if (request.cookies.authToken) {
      return NextResponse.rewrite(new URL('/auth/dashboard', request.url))
    } else {
      return NextResponse.rewrite(new URL('/public/dashboard', request.url))
    }
  }
}

Dans ce cas, vous devriez utiliser le code suivant dans votre composant <Link /> :

'use client'

import Link from 'next/link'
import useIsAuthed from './hooks/useIsAuthed' // Votre hook d'authentification

export default function Home() {
  const isAuthed = useIsAuthed()
  const path = isAuthed ? '/auth/dashboard' : '/public/dashboard'
  return (
    <Link as="/dashboard" href={path}>
      Dashboard
    </Link>
  )
}

Bon à savoir : Si vous utilisez des Routes dynamiques, vous devrez adapter vos props as et href. Par exemple, si vous avez une Route dynamique comme /dashboard/authed/[user] que vous souhaitez présenter différemment via le middleware, vous écrirez : <Link href={{ pathname: '/dashboard/authed/[user]', query: { user: username } }} as="/dashboard/[user]">Profile</Link>.

Blocage de la navigation

Vous pouvez utiliser la prop onNavigate pour bloquer la navigation lorsque certaines conditions sont remplies, comme lorsqu'un formulaire contient des modifications non enregistrées. Lorsque vous devez bloquer la navigation dans plusieurs composants de votre application (par exemple empêcher la navigation depuis n'importe quel lien pendant qu'un formulaire est en cours de modification), React Context offre une solution propre pour partager cet état de blocage. Commencez par créer un contexte pour suivre l'état de blocage de la navigation :

'use client'

import { createContext, useState, useContext } from 'react'

interface NavigationBlockerContextType {
  isBlocked: boolean
  setIsBlocked: (isBlocked: boolean) => void
}

export const NavigationBlockerContext =
  createContext<NavigationBlockerContextType>({
    isBlocked: false,
    setIsBlocked: () => {},
  })

export function NavigationBlockerProvider({
  children,
}: {
  children: React.ReactNode
}) {
  const [isBlocked, setIsBlocked] = useState(false)

  return (
    <NavigationBlockerContext.Provider value={{ isBlocked, setIsBlocked }}>
      {children}
    </NavigationBlockerContext.Provider>
  )
}

export function useNavigationBlocker() {
  return useContext(NavigationBlockerContext)
}

Créez un composant de formulaire utilisant le contexte :

'use client'

import { useNavigationBlocker } from '../contexts/navigation-blocker'

export default function Form() {
  const { setIsBlocked } = useNavigationBlocker()

  return (
    <form
      onSubmit={(e) => {
        e.preventDefault()
        setIsBlocked(false)
      }}
      onChange={() => setIsBlocked(true)}
    >
      <input type="text" name="name" />
      <button type="submit">Enregistrer</button>
    </form>
  )
}

Créez un composant Link personnalisé qui bloque la navigation :

'use client'

import Link from 'next/link'
import { useNavigationBlocker } from '../contexts/navigation-blocker'

interface CustomLinkProps extends React.ComponentProps<typeof Link> {
  children: React.ReactNode
}

export function CustomLink({ children, ...props }: CustomLinkProps) {
  const { isBlocked } = useNavigationBlocker()

  return (
    <Link
      onNavigate={(e) => {
        if (
          isBlocked &&
          !window.confirm('Vous avez des modifications non enregistrées. Quitter quand même ?')
        ) {
          e.preventDefault()
        }
      }}
      {...props}
    >
      {children}
    </Link>
  )
}

Créez un composant de navigation :

'use client'

import { CustomLink as Link } from './custom-link'

export default function Nav() {
  return (
    <nav>
      <Link href="/">Accueil</Link>
      <Link href="/about">À propos</Link>
    </nav>
  )
}

Enfin, enveloppez votre application avec le NavigationBlockerProvider dans la racine de votre layout et utilisez les composants dans votre page :

import { NavigationBlockerProvider } from './contexts/navigation-blocker'

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body>
        <NavigationBlockerProvider>{children}</NavigationBlockerProvider>
      </body>
    </html>
  )
}

Puis, utilisez les composants Nav et Form dans votre page :

import Nav from './components/nav'
import Form from './components/form'

export default function Page() {
  return (
    <div>
      <Nav />
      <main>
        <h1>Bienvenue sur le Dashboard</h1>
        <Form />
      </main>
    </div>
  )
}

Lorsqu'un utilisateur tente de naviguer en utilisant CustomLink alors que le formulaire contient des modifications non enregistrées, il sera invité à confirmer avant de quitter.

Historique des versions

VersionChangements
v15.3.0Ajout de l'API onNavigate
v13.0.0Ne nécessite plus une balise enfant <a>. Un codemod est fourni pour mettre à jour automatiquement votre codebase.
v10.0.0Les props href pointant vers une route dynamique sont automatiquement résolues et ne nécessitent plus de prop as.
v8.0.0Amélioration des performances de préchargement.
v1.0.0Introduction de next/link.