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

Liaisons bidirectionnelles ($bindable)

2 min de lecture ·
Dans cette leçon4

Parfois, tu as besoin qu'un enfant puisse modifier les données du parent. Utilise $bindable !

$bindable en Svelte 5

<!-- SearchInput.svelte -->
<script>
  let { value = $bindable('') } = $props();
</script>

<input bind:value placeholder="Chercher un guerrier..." />
<!-- Parent.svelte -->
<script>
  import SearchInput from './SearchInput.svelte';

  let searchQuery = $state('');
</script>

<SearchInput bind:value={searchQuery} />
<p>Tu cherches : {searchQuery}</p>

Quand utiliser $bindable ?

Bons cas d'usage :

  • Champs de formulaire
  • Composants contrôlés (select, slider)
  • Modale avec contrôle de visibilité

À éviter quand :

  • Un flux de données à sens unique suffit
  • La logique de mise à jour est complexe
  • Il y a plusieurs sources de vérité

Exemple : Slider

<!-- VolumeSlider.svelte -->
<script>
  let { value = $bindable(50), min = 0, max = 100 } = $props();
</script>

<div class="slider">
  <input
    type="range"
    bind:value
    {min}
    {max}
  />
  <span>{value}</span>
</div>

<style>
  .slider {
    display: flex;
    align-items: center;
    gap: 1rem;
  }
</style>
<!-- Parent.svelte -->
<script>
  import VolumeSlider from './VolumeSlider.svelte';

  let warHornVolume = $state(75);
</script>

<h3>Volume du cor de guerre</h3>
<VolumeSlider bind:value={warHornVolume} />
<p>Volume actuel : {warHornVolume}%</p>

Exemple : Modale

<!-- Modal.svelte -->
<script>
  let { open = $bindable(false), title, children } = $props();

  function close() {
    open = false;
  }
</script>

{#if open}
  <div class="overlay" role="presentation" onclick={close}>
    <div
      class="modal"
      role="dialog"
      aria-modal="true"
      tabindex="-1"
      onclick={(e) => e.stopPropagation()}
      onkeydown={(e) => e.key === 'Escape' && close()}
    >
      <header>
        <h2>{title}</h2>
        <button onclick={close}>×</button>
      </header>
      <main>
        {@render children()}
      </main>
    </div>
  </div>
{/if}

Un clic sur le fond ferme la fenêtre, et e.stopPropagation() (autrefois le modificateur |stopPropagation) empêche un clic à l'intérieur de la fenêtre d'atteindre le fond.

<!-- Parent.svelte -->
<script>
  import Modal from './Modal.svelte';

  let showModal = $state(false);
</script>

<button onclick={() => showModal = true}>
  Ouvrir la modale
</button>

<Modal bind:open={showModal} title="Conseil de guerre">
  <p>Nous préparons une attaque à l'aube !</p>
</Modal>
Code de cette leçon : App.svelte
<script>
  // $bindable: the child changes the parent's state through bind:value
  import CoinCounter from './CoinCounter.svelte';

  let treasury = $state({ gold: 10, silver: 25, copper: 40 });

  let worth = $derived(treasury.gold * 100 + treasury.silver * 10 + treasury.copper);
</script>

<main class="treasury">
  <h1>Viking Treasury</h1>
  <p>$bindable props: each counter writes straight into the chest</p>

  <div class="counters">
    <CoinCounter name="Gold" bind:value={treasury.gold} />
    <CoinCounter name="Silver" bind:value={treasury.silver} />
    <CoinCounter name="Copper" bind:value={treasury.copper} />
  </div>

  <div class="total">
    <h2>Worth in copper: {worth}</h2>
    <button onclick={() => (treasury = { gold: 0, silver: 0, copper: 0 })}>
      Empty the chest
    </button>
  </div>
</main>

<style>
  .treasury {
    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;
  }

  .counters {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1rem;
    margin: 2rem 0;
  }

  .total {
    text-align: center;
    background: rgba(212, 175, 55, 0.2);
    border: 2px solid #d4af37;
    border-radius: 8px;
    padding: 1rem;
  }

  .total h2 {
    color: #ffd700;
    margin: 0 0 0.75rem 0;
  }

  .total button {
    padding: 0.5rem 1rem;
    background: #3d2914;
    color: #e8d5b7;
    border: 1px solid #d4af37;
    border-radius: 4px;
    cursor: pointer;
  }
</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 marquer une prop comme bindable dans Svelte 5 ?

Tâches pratiques dans le jeu

  • Éditeur de code

    Complète le code pour que value soit bindable avec une valeur par défaut de ''

Articles utiles