Cours Svelte et SvelteKit · Module 4: Props et événements

Events - Communiquer vers le haut

3 min de lecture ·
Dans cette leçon4

Les Events permettent aux composants enfants d'envoyer des informations aux parents, comme des rapports d'éclaireurs au jarl ! En Svelte 5, on le fait avec de simples fonctions transmises en props.

Callback Props (Svelte 5)

Le parent transmet une fonction en prop, et l'enfant l'appelle dans un attribut d'événement comme onclick :

<!-- WarriorCard.svelte -->
<script>
  let { warrior, onSelect, onDelete } = $props();
</script>

<div class="card">
  <h3>{warrior.name}</h3>
  <button onclick={() => onSelect(warrior)}>
    Choisir
  </button>
  <button onclick={() => onDelete(warrior.id)}>
    Supprimer
  </button>
</div>
<!-- Parent.svelte -->
<script>
  import WarriorCard from './WarriorCard.svelte';

  let warriors = $state([
    { id: 1, name: 'Ragnar' },
    { id: 2, name: 'Bjorn' }
  ]);

  let selected = $state(null);

  function handleSelect(warrior) {
    selected = warrior;
    console.log('Choisi :', warrior.name);
  }

  function handleDelete(id) {
    warriors = warriors.filter(w => w.id !== id);
  }
</script>

{#each warriors as warrior (warrior.id)}
  <WarriorCard
    {warrior}
    onSelect={handleSelect}
    onDelete={handleDelete}
  />
{/each}

{#if selected}
  <p>Choisi : {selected.name}</p>
{/if}

Commence le nom de ces props par on (onSelect, onDelete) : on voit tout de suite que ce sont des événements. Les données arrivent au parent directement comme arguments de la fonction.

Événements des éléments et modificateurs

En Svelte 5, les événements DOM sont de simples attributs : onclick, onkeydown, onsubmit. Les modificateurs comme |preventDefault ont disparu : tu appelles la méthode correspondante dans le gestionnaire :

<script>
  let report = $state('');

  function sendReport(e) {
    e.preventDefault(); // autrefois on:submit|preventDefault
    report = 'Rapport envoyé au jarl !';
  }
</script>

<form onsubmit={sendReport}>
  <input placeholder="Texte du rapport" />
  <button>Envoyer</button>
</form>
<p>{report}</p>

Transmettre des événements (forwarding)

Un composant qui enveloppe un élément (par exemple un bouton) reçoit un callback dans ses props et le confie à l'élément :

<!-- Button.svelte -->
<script>
  let { onclick, children } = $props();
</script>

<button {onclick}>
  {@render children()}
</button>

Tu peux aussi transmettre d'un coup toutes les autres props à l'élément, avec onclick, class ou disabled :

<!-- Button.svelte -->
<script>
  let { children, ...rest } = $props();
</script>

<button {...rest}>
  {@render children()}
</button>
<!-- Parent.svelte -->
<script>
  import Button from './Button.svelte';

  function handleClick() {
    alert('Au combat !');
  }
</script>

<Button onclick={handleClick}>
  Clique-moi
</Button>

Un callback traverse un composant intermédiaire comme n'importe quelle autre prop : App transmet onAttack à Battle, et Battle le passe à Fighter (vois l'éditeur ci-dessous).

Svelte 4 (legacy) : createEventDispatcher

Dans l'ancien code, tu verras createEventDispatcher et les directives on:. En Svelte 5, createEventDispatcher est obsolète, et au lieu de <button on:click> (forwarding sans gestionnaire) on transmet un callback comme ci-dessus. Sache reconnaître cette écriture, mais utilise les callback props dans le nouveau code.

<!-- WarriorCard.svelte - Svelte 4 (legacy) -->
<script>
  import { createEventDispatcher } from 'svelte';

  export let warrior;

  const dispatch = createEventDispatcher();
</script>

<button on:click={() => dispatch('select', warrior)}>Choisir</button>
<!-- Parent.svelte - Svelte 4 (legacy) -->
<WarriorCard {warrior} on:select={(e) => selected = e.detail} />

Les données arrivaient dans e.detail. Avec les callback props, tu les reçois directement comme argument de la fonction.

Code de cette leçon : App.svelte
<script>
  // Callback props pass through components like any other prop
  import Battle from './Battle.svelte';

  let battleLog = $state([]);

  function handleAttack(entry) {
    battleLog = [...battleLog, entry].slice(-5);
  }
</script>

<main class="arena">
  <h1>Battle Arena</h1>
  <p>App passes onAttack to Battle, Battle passes it on to each Fighter</p>

  <Battle onAttack={handleAttack} />

  <div class="log">
    <h2>Battle log:</h2>
    {#each battleLog as entry}
      <p>{entry.attacker} dealt {entry.damage} damage!</p>
    {/each}
    {#if battleLog.length === 0}
      <p class="empty">No attacks...</p>
    {/if}
  </div>
</main>

<style>
  .arena {
    font-family: 'Georgia', serif;
    max-width: 600px;
    margin: 0 auto;
    padding: 2rem;
    background: #1a0f0a;
    color: #e8d5b7;
    min-height: 100vh;
  }

  h1 {
    color: #d4af37;
    text-align: center;
  }

  p {
    text-align: center;
    color: #8b7355;
  }

  .log {
    margin-top: 2rem;
    background: rgba(0,0,0,0.3);
    border-radius: 8px;
    padding: 1rem;
  }

  .log h2 {
    color: #d4af37;
    font-size: 1rem;
    margin-top: 0;
  }

  .log p {
    text-align: left;
    margin: 0.5rem 0;
    padding: 0.5rem;
    background: rgba(139, 0, 0, 0.2);
    border-radius: 4px;
  }

  .empty {
    color: #666;
    font-style: italic;
  }
</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. Quelle est la méthode privilégiée pour envoyer des événements dans Svelte 5 ?

Tâches pratiques dans le jeu

  • Éditeur de code

    Complète le code pour qu'un clic sur le bouton appelle la fonction onSelect

Articles utiles