Cours Svelte et SvelteKit · Module 11: Routage SvelteKit

Layouts

2 min de lecture ·
Dans cette leçon4

+layout.svelte

<!-- src/routes/+layout.svelte -->
<script>
  import Header from '#lib/components/Header.svelte';
  import Footer from '#lib/components/Footer.svelte';

  let { children } = $props();
</script>

<Header />

<main>
  {@render children()}  <!-- La page s'affiche ici -->
</main>

<Footer />

<style>
  main {
    max-width: 1200px;
    margin: 0 auto;
    padding: 1rem;
  }
</style>

Le layout reçoit le contenu de la page sous forme de snippet children et l'affiche avec la balise {@render children()}. En Svelte 4, c'était le rôle de l'élément <slot />, devenu obsolète en Svelte 5.

L'alias #lib est le successeur de $lib dans SvelteKit 3 : il pointe vers le dossier src/lib (une entrée imports dans package.json), et tu importes les modules JS avec leur extension, par exemple #lib/utils.js.

Layouts imbriqués

src/routes/
├── +layout.svelte           # Layout principal
├── +page.svelte             # Page d'accueil
└── dashboard/
    ├── +layout.svelte       # Layout du dashboard (imbriqué)
    ├── +page.svelte         # /dashboard
    └── settings/
        └── +page.svelte     # /dashboard/settings
<!-- src/routes/dashboard/+layout.svelte -->
<script>
  import Sidebar from './Sidebar.svelte';

  let { children } = $props();
</script>

<div class="dashboard-layout">
  <Sidebar />
  <div class="content">
    {@render children()}
  </div>
</div>

Données de layout

// src/routes/+layout.js
export function load() {
  return {
    user: { name: 'Ragnar' }
  };
}
<!-- src/routes/+layout.svelte -->
<script>
  let { data, children } = $props();
</script>

<nav>
  Connecté en tant que : {data.user.name}
</nav>

{@render children()}

Réinitialiser le layout

<!-- src/routes/fullscreen/+page@.svelte -->
<!-- @ réinitialise vers le layout racine -->
<h1>Page plein écran sans layout</h1>
Code de cette leçon : App.svelte
<script>
  // Layout et layouts imbriqués

  let showSidebar = $state(true);
</script>

<div class="app-layout">
  <!-- +layout.svelte (principal) -->
  <header class="header">
    <h1>Application Viking</h1>
    <nav>
      <a href="/">Accueil</a>
      <a href="/warriors">Guerriers</a>
      <a href="/ships">Navires</a>
    </nav>
  </header>

  <div class="main-content">
    {#if showSidebar}
      <!-- barre latérale depuis (warriors)/+layout.svelte -->
      <aside class="sidebar">
        <h3>Filtre des guerriers</h3>
        <ul>
          <li><a href="/warriors?status=all">Tous</a></li>
          <li><a href="/warriors?status=alive">Vivant</a></li>
          <li><a href="/warriors?status=dead">Walhalla</a></li>
        </ul>
      </aside>
    {/if}

    <!-- +page.svelte -->
    <main class="page">
      <button onclick={() => showSidebar = !showSidebar}>
        {showSidebar ? 'Masquer' : 'Afficher'} la barre latérale
      </button>

      <h2>Contenu de la page</h2>
      <p>C’est ici que le layout affiche la page : <code>{'{@render children()}'}</code></p>

      <div class="structure">
        <pre>
src/routes/
├── +layout.svelte        ← En-tête (partagé)
├── +page.svelte          ← Accueil
└── warriors/
    ├── +layout.svelte    ← Barre latérale (pour warriors)
    └── +page.svelte      ← Liste des guerriers
        </pre>
      </div>
    </main>
  </div>

  <!-- Pied de page depuis le layout principal -->
  <footer class="footer">
    <p>© 2024 Application Viking - Propulsé par SvelteKit</p>
  </footer>
</div>

<style>
  .app-layout {
    font-family: 'Georgia', serif;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    background: #0a1628;
    color: #b8d4f7;
  }

  .header {
    background: #1e3a5f;
    padding: 1rem 2rem;
    display: flex;
    justify-content: space-between;
    align-items: center;
  }

  .header h1 {
    margin: 0;
    color: #ffd700;
    font-size: 1.5rem;
  }

  .header nav {
    display: flex;
    gap: 1rem;
  }

  .header a {
    color: #b8d4f7;
    text-decoration: none;
  }

  .main-content {
    flex: 1;
    display: flex;
  }

  .sidebar {
    width: 200px;
    background: rgba(74, 144, 217, 0.1);
    padding: 1rem;
    border-right: 1px solid #4a90d9;
  }

  .sidebar h3 {
    color: #4a90d9;
    font-size: 1rem;
    margin-top: 0;
  }

  .sidebar ul {
    list-style: none;
    padding: 0;
  }

  .sidebar li {
    margin: 0.5rem 0;
  }

  .sidebar a {
    color: #b8d4f7;
    text-decoration: none;
  }

  .page {
    flex: 1;
    padding: 2rem;
  }

  button {
    padding: 0.5rem 1rem;
    background: #1e3a5f;
    color: #b8d4f7;
    border: 1px solid #4a90d9;
    border-radius: 4px;
    cursor: pointer;
    margin-bottom: 1rem;
  }

  h2 {
    color: #4a90d9;
  }

  code {
    background: rgba(0,0,0,0.5);
    padding: 0.2rem 0.5rem;
    border-radius: 4px;
  }

  .structure pre {
    background: rgba(0,0,0,0.5);
    padding: 1rem;
    border-radius: 4px;
    font-size: 0.85rem;
  }

  .footer {
    background: #1e3a5f;
    padding: 1rem;
    text-align: center;
    font-size: 0.9rem;
  }
</style>

Entrées de la documentation utilisées dans cette leçon

Tu as repéré une erreur dans cette leçon ?

Teste tes connaissances

Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.

  1. 1. Comment affiches-tu le contenu de la page dans +layout.svelte (Svelte 5) ?

Articles utiles