W3docs

Déclenchement d'événements personnalisés en JavaScript

Créez et déclenchez des événements personnalisés en JavaScript avec CustomEvent et dispatchEvent, transmettez des données via detail et découpled les composants grâce aux événements.

Déclenchement d'événements personnalisés en JavaScript

Le navigateur déclenche automatiquement des événements natifs tels que click, submit et keydown. Mais JavaScript vous permet également de créer et de déclencher vos propres événements sur n'importe quel nœud du DOM, puis de les écouter avec le même addEventListener() que vous utilisez déjà pour les événements natifs.

C'est le fondement d'une conception d'application faiblement couplée : une partie de votre code annonce qu'il s'est passé quelque chose (« données chargées », « panier mis à jour ») sans savoir ni se soucier qui écoute. Cette page explique comment créer des événements personnalisés avec le constructeur CustomEvent, y attacher des données, les déclencher avec dispatchEvent(), et éviter les pièges courants.

Créer un événement personnalisé

Utilisez le constructeur CustomEvent. Le premier argument est le type d'événement (le nom que vous écouterez ensuite) ; le second est un objet d'options :

let event = new CustomEvent("myEvent", {
  detail: { message: "This is a custom event!" },
  bubbles: true,
  cancelable: true
});

Les trois options que vous utiliserez le plus souvent sont :

  • detail — toute valeur (object, string, nombre) que vous souhaitez attacher à l'événement. L'écouteur la récupère via event.detail. C'est le canal dédié aux données personnalisées ; les propriétés des événements natifs sont en lecture seule.
  • bubbles — lorsque true, l'événement remonte à travers les éléments ancêtres après le déclenchement, de sorte qu'un écouteur sur un parent (ou sur document) peut le capturer. Par défaut false.
  • cancelable — lorsque true, un écouteur peut appeler event.preventDefault() pour signaler que l'action par défaut doit être ignorée. Par défaut false.

CustomEvent vs. Event

Il existe aussi un constructeur Event simple, mais il ne peut pas transporter de données — il ne possède pas de detail. Préférez toujours CustomEvent lorsque vous devez transmettre des informations avec l'événement :

// No way to attach data here:
let bare = new Event("ping", { bubbles: true });

// Use CustomEvent to send a payload:
let withData = new CustomEvent("ping", {
  bubbles: true,
  detail: { at: Date.now() }
});

Déclencher l'événement

Un événement créé ne fait rien tant que vous ne le déclenchez pas sur un élément avec dispatchEvent() :

let target = document.getElementById("box");
target.dispatchEvent(event);

Deux points importants à connaître sur dispatchEvent() :

  1. Il s'exécute de manière synchrone — contrairement à setTimeout, les écouteurs s'exécutent immédiatement, avant la ligne qui suit dispatchEvent().
  2. Il retourne un boolean : false si l'événement était cancelable et qu'un écouteur a appelé preventDefault(), sinon true. Cela permet au code qui a déclenché l'événement de réagir à un « veto » :
let cancelled = !target.dispatchEvent(event);
if (cancelled) {
  console.log("A listener prevented the default action.");
}

Vous pouvez déclencher l'événement sur n'importe quel élément. Déclencher sur document fonctionne car les événements qui remontent l'atteignent, mais déclencher sur l'élément spécifique qui « possède » l'événement (et laisser la propagation faire le reste) garde vos écouteurs ciblés et évite les gestionnaires globaux accidentels.

Écouter un événement personnalisé

Il n'y a pas d'API spéciale côté écoute — addEventListener() fonctionne exactement comme pour click. Les données arrivent via event.detail :

element.addEventListener("myEvent", function (event) {
  console.log(event.detail.message); // "This is a custom event!"
});

Exemples pratiques

Exemple 1 : Communication entre composants

Supposons que deux parties indépendantes d'une page doivent communiquer sans détenir de références directes l'une vers l'autre. L'une déclenche un événement personnalisé ; l'autre écoute. Comme l'événement bubbles, l'écouteur peut être placé sur document :

<button id="sender">Send Message</button>
// Listener in another component
document.addEventListener('componentMessage', function(event) {
  alert('Received message: ' + event.detail.message);
});

document.getElementById('sender').addEventListener('click', function() {
  // Create and dispatch the custom event
  let customEvent = new CustomEvent('componentMessage', {
    detail: { message: 'Hello from another component!' },
    bubbles: true,
    cancelable: true
  });
  document.dispatchEvent(customEvent);
});

Fonctionnement :

  • Un clic sur le bouton crée et déclenche un événement componentMessage transportant un message dans detail.
  • Un écouteur ailleurs capture l'événement et y réagit. Aucune des deux parties n'importe l'autre — le nom de l'événement est le seul contrat.

Exemple 2 : Mise à jour de l'interface après une modification de données

Les événements personnalisés vous permettent de séparer la logique des données de la logique d'affichage. La couche de données annonce dataUpdated ; la couche d'interface écoute et se rafraîchit. Ici, la mise à jour est déclenchée après un court délai pour simuler une requête asynchrone :

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Custom Event UI Update Example</title>
</head>
<body>
<h1>User Status</h1>
<div id="userInfo">Loading user information...</div>

<script>
  // Function to simulate a data update
  function updateData() {
    let dataUpdateEvent = new CustomEvent('dataUpdated', {
      detail: { data: { username: 'user123', status: 'active' } }
    });
    document.dispatchEvent(dataUpdateEvent);
  }

  // UI component listening for data updates
  document.addEventListener('dataUpdated', function(event) {
    let userData = event.detail.data;
    document.getElementById('userInfo').innerHTML =
      `Username: <strong>${userData.username}</strong>, Status: <strong>${userData.status}</strong>`;
  });

  // Trigger the update after 2 seconds
  setTimeout(updateData, 2000);
</script>
</body>
</html>

Fonctionnement :

  • Après deux secondes, updateData() déclenche un événement dataUpdated avec les nouvelles données dans detail.
  • L'écouteur de l'interface lit event.detail.data et met à jour la page. La fonction qui a produit les données ne touche jamais directement le DOM.

Annuler un événement personnalisé

Lorsqu'un événement est cancelable, un écouteur peut appeler preventDefault(). Le déclencheur reçoit alors une valeur de retour false de dispatchEvent() et peut ignorer son comportement par défaut — le même schéma que le navigateur utilise pour la soumission de formulaire ou les clics sur les liens. Cet extrait s'exécute dans Node et illustre le flux synchrone :

let target = new EventTarget();

target.addEventListener("save", (event) => {
  // Veto the save
  event.preventDefault();
});

let event = new CustomEvent("save", { cancelable: true });
let notCancelled = target.dispatchEvent(event);

console.log(notCancelled);          // false
console.log(event.defaultPrevented); // true

EventTarget est l'interface de base dont héritent les nœuds du DOM, la même logique s'applique donc que vous déclenchiez l'événement sur un élément dans le navigateur ou sur un EventTarget autonome.

Conclusion

Les événements personnalisés vous offrent un moyen propre et sans framework de connecter les différentes parties d'une application. Créez-les avec CustomEvent, attachez une charge utile via detail, déclenchez-les avec dispatchEvent() et écoutez-les avec le familier addEventListener(). Définissez bubbles: true lorsqu'un parent doit capturer l'événement, et cancelable: true lorsque le déclencheur doit respecter le veto d'un écouteur. Le résultat est un code où les modules communiquent via des événements nommés plutôt que par des références directes — plus facile à tester, à étendre et à maintenir.

Pour aller plus loin, découvrez comment les événements traversent le DOM dans bubbling et capturing, comment les écouteurs sont attachés dans la gestion des événements dans le DOM, et comment preventDefault() affecte les actions par défaut du navigateur.

Pratique

Pratique
Quelles affirmations concernant les événements personnalisés en JavaScript sont correctes ?
Quelles affirmations concernant les événements personnalisés en JavaScript sont correctes ?
Was this page helpful?