Journal

Stimulus : Values, Targets et Outlets pour des controllers robustes

Journal du dimanche 23 août 2026, généré le 23 août à 19:38

L'API Values : typer l'état d'un controller

Passé les premiers data-controller et data-target, la vraie puissance de Stimulus tient dans son API Values. Elle transforme les attributs data-* en propriétés JavaScript typées, avec sérialisation/désérialisation automatique et un callback déclenché à chaque changement.

// controllers/slider_controller.js
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static values = { index: { type: Number, default: 0 }, autoplay: Boolean }
  static targets = ["slide"]

  indexValueChanged(value, previousValue) {
    this.slideTargets.forEach((el, i) => {
      el.classList.toggle("is-active", i === value)
    })
  }

  next() {
    this.indexValue = (this.indexValue + 1) % this.slideTargets.length
  }
}

Le HTML reste déclaratif : data-slider-index-value="2" ou data-slider-autoplay-value="true" suffisent à initialiser l'état. Le callback indexValueChanged évite d'avoir à relire le DOM manuellement à chaque interaction.

Callbacks de cycle de vie sur les targets

Depuis Stimulus 3, chaque target déclenche aussi ses propres hooks : slideTargetConnected(element) et slideTargetDisconnected(element). C'est précieux avec Turbo Streams, où des éléments apparaissent et disparaissent dynamiquement sans rechargement complet du controller.

Outlets : faire communiquer plusieurs controllers

Avant les outlets, faire dialoguer deux controllers passait souvent par des CustomEvent bricolés. L'API Outlets formalise cette relation : un controller déclare une dépendance vers un autre via static outlets = ["modal"], reliée dans le HTML par data-slider-modal-outlet=".modal".

static outlets = ["modal"]

open() {
  this.modalOutlet.show()
}

modalOutletConnected(outlet, element) {
  outlet.registerTrigger(this)
}

Chaque outlet expose l'instance du controller cible (avec accès direct à ses méthodes publiques) ainsi que son élément DOM, et déclenche ses propres callbacks Connected/Disconnected quand la cible entre ou sort du document.

Actions avec paramètres

Autre point souvent sous-utilisé : les action parameters. Plutôt que de relire un data-id à la main dans le handler, on le déclare directement sur l'élément déclencheur : data-action="click->slider#goTo" data-slider-index-param="3", récupéré ensuite via goTo({ params: { index } }).

Bonnes pratiques à garder en tête

  • Un controller = une responsabilité ; préférez plusieurs petits controllers reliés par outlets plutôt qu'un god-controller.
  • Utilisez l'API Classes (static classes = ["active"]) pour éviter de coder en dur des noms de classes CSS.
  • Ne dupliquez pas ce que Turbo gère déjà (navigation, remplacement partiel) : Stimulus doit rester la couche comportementale, pas un mini-framework SPA.
  • Préfixez les méthodes internes non destinées aux actions pour clarifier l'API publique du controller.