Frontend·2 min de lecture

Next.js : les Layouts

L'idée clé

Un layout est une coquille UI qui reste affichée pendant que les pages enfants changent. Quand l'user navigue de /admin/produits à /admin/clients, le sidebar (dans app/admin/layout.tsx) ne re-monte pas. Seul le page.tsx est échangé.

Ça donne :

  • Performances : le sidebar ne se re-télécharge pas, l'état est préservé (scroll, formulaires, etc.)
  • UI cohérente : header/footer/nav identiques partout sans copier-coller
  • Imbrication : layouts s'enchaînent (root → admin → produits) — chacun englobe ses enfants

Anatomie

// app/admin/layout.tsx
export default function AdminLayout({ children }: { children: React.ReactNode }) {
  return (
    <div className="flex">
      <Sidebar />
      <main>{children}</main>   {/* ← la page de l'URL est rendue ici */}
    </div>
  );
}

La prop magique : children. Next y injecte automatiquement la page.tsx qui correspond à l'URL, ou un layout enfant si l'arborescence en a un.

Le root layout (app/layout.tsx)

C'est le seul layout obligatoire. Il doit contenir les balises <html> et <body> (les autres layouts non, juste des <div> etc.).

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

Tout ce que tu mets là (theme provider, script de thème, fonts) est chargé sur toutes les pages.

Imbrication concrète chez wari

Quand un user visite /admin/produits/42 :

RootLayout (app/layout.tsx)
AdminLayout (app/admin/layout.tsx)         ← AdminShell, sidebar
    → ProduitsLayout ? (si existe)
ProductDetailPage (app/admin/produits/[id]/page.tsx)

Chaque layout englobe son enfant. Le sidebar de AdminLayout reste fixe pendant que l'user passe d'un produit à un autre dans /admin/produits/[id].

Pour comparer à ce que tu connais

Si tu as fait du Django : layout.tsx joue le rôle d'un template base.html qu'on hérite via {% extends %}. Sauf que :

  • L'imbrication est automatique (par arborescence)
  • Le layout est persistant côté client (pas re-rendu à chaque nav)

Piège classique

Ne mets pas d'état (useState) qui doit dépendre de l'URL dans un layout — il ne re-monte pas. Si tu changes de page, le useState garde sa valeur d'avant. Pour de l'état lié à l'URL, utilise useSearchParams() ou mets le state dans page.tsx qui, lui, re-monte.

Dans ton code wari

Pour aller plus loin : Doc officielle Next.js — Layouts