> Maîtriser les événements JavaScript : addEventListener, objet event, clic, clavier, propagation (bubbling/capture), preventDefault, stopPropagation, délégation et removeEventListener.

*Source : https://coder-studio.com/tutoriels/event-listener-javascript/*

---

[// Web](https://coder-studio.com/tutoriels/)

# Les événements en JavaScript (addEventListener)

Par **Kévin Papot** · publié le 20 janvier 2026

Les **événements** sont ce qui rend une page web vivante : un clic, une frappe au clavier, l’envoi d’un formulaire, le survol d’un bouton… À chaque interaction, le navigateur émet un _événement_ que votre JavaScript peut écouter pour réagir. La méthode `addEventListener` est l’outil central de cette écoute. Ce guide couvre son fonctionnement, l’objet `event`, les types courants, la propagation entre éléments, l’annulation du comportement par défaut, la puissante technique de délégation, et le nettoyage des écouteurs.

## addEventListener : écouter un événement

La méthode `addEventListener` s’attache à un élément du DOM. Elle prend le **type** d’événement (une chaîne comme `"click"`) et une **fonction de rappel** (le _callback_) exécutée à chaque déclenchement.

```
const bouton = document.querySelector("#valider");

bouton.addEventListener("click", () => {
  console.log("Bouton cliqué !");
});
```

À chaque clic sur le bouton, la fonction s’exécute. On peut attacher **plusieurs** écouteurs au même élément et au même type sans qu’ils s’écrasent, ce qui est un gros avantage sur l’ancienne syntaxe `element.onclick = ...` (limitée à un seul gestionnaire). Manipuler ces éléments suppose de savoir les [sélectionner dans le DOM](https://coder-studio.com/tutoriels/manipuler-dom-javascript/), étape préalable à toute écoute.

## L’objet event

Le callback reçoit automatiquement un argument : l’objet `event`, qui décrit ce qui s’est passé. Il contient des dizaines d’informations utiles selon le type d’événement.

```
bouton.addEventListener("click", (event) => {
  console.log(event.type);          // "click"
  console.log(event.target);        // l'élément cliqué
  console.log(event.clientX, event.clientY); // coordonnées du curseur
});
```

Deux propriétés reviennent constamment :

-   `event.target` : l’élément qui a **réellement** déclenché l’événement (celui sous le curseur, par exemple) ;
-   `event.currentTarget` : l’élément sur lequel l’écouteur est **attaché** (souvent un parent). La distinction devient cruciale avec la propagation, vue plus bas.

## Les types d’événements courants

Il existe des centaines de types d’événements. Voici les familles les plus utilisées au quotidien.

```
// Souris
element.addEventListener("click", gerer);
element.addEventListener("dblclick", gerer);
element.addEventListener("mouseenter", gerer);
element.addEventListener("mouseleave", gerer);

// Clavier
input.addEventListener("keydown", gerer);
input.addEventListener("keyup", gerer);

// Formulaire
formulaire.addEventListener("submit", gerer);
input.addEventListener("input", gerer);   // à chaque frappe
select.addEventListener("change", gerer);  // après validation du choix

// Fenêtre et document
window.addEventListener("resize", gerer);
window.addEventListener("scroll", gerer);
document.addEventListener("DOMContentLoaded", gerer); // page prête
```

### Exemple : lire une touche du clavier

Les événements clavier exposent la touche pressée via `event.key`.

```
const champ = document.querySelector("#recherche");

champ.addEventListener("keydown", (event) => {
  if (event.key === "Enter") {
    console.log("Recherche lancée :", champ.value);
  }
  if (event.key === "Escape") {
    champ.value = "";
  }
});
```

## La propagation : bubbling et capture

Quand vous cliquez sur un élément imbriqué dans d’autres, l’événement ne concerne pas que lui. Il **se propage**. Par défaut, il suit la phase de _bubbling_ (remontée) : il part de l’élément cliqué et remonte vers ses parents, jusqu’à `document`.

```
// HTML : <div id="carte"><button id="btn">Cliquer</button></div>

document.querySelector("#carte").addEventListener("click", () => {
  console.log("Div carte");
});

document.querySelector("#btn").addEventListener("click", () => {
  console.log("Bouton");
});

// Un clic sur le bouton affiche :
// "Bouton" puis "Div carte" — l'événement remonte
```

Il existe aussi une phase de _capture_ (descente), qui va des parents vers la cible, activée en passant `true` (ou `{ capture: true }`) en troisième argument. On l’utilise rarement, mais il faut connaître son existence.

```
document.querySelector("#carte").addEventListener("click", () => {
  console.log("Capture parent en premier");
}, true);
```

## preventDefault et stopPropagation

Deux méthodes de l’objet `event` permettent de reprendre le contrôle. Elles sont souvent confondues alors qu’elles font des choses distinctes.

`preventDefault()` **annule le comportement par défaut** du navigateur : empêcher un lien de naviguer, un formulaire de recharger la page, une case de se cocher.

```
formulaire.addEventListener("submit", (event) => {
  event.preventDefault(); // pas de rechargement de page
  console.log("Envoi géré en JavaScript");
  // ... traitement, envoi via fetch, etc.
});
```

`stopPropagation()` **arrête la propagation** : l’événement ne remontera pas aux parents. Utile pour éviter qu’un clic sur un élément interne déclenche l’écouteur d’un conteneur.

```
document.querySelector("#btn").addEventListener("click", (event) => {
  event.stopPropagation(); // "Div carte" ne s'affichera plus
  console.log("Bouton seulement");
});
```

Retenez la distinction : `preventDefault` agit sur le **navigateur**, `stopPropagation` agit sur les **autres écouteurs**.

## La délégation d’événements

Voici une technique aussi élégante qu’essentielle. Plutôt que d’attacher un écouteur à chaque élément d’une liste (coûteux, et inopérant pour les éléments ajoutés plus tard), on attache **un seul** écouteur au parent commun et on utilise `event.target` pour savoir quel enfant a été cliqué. C’est le _bubbling_ qui rend cela possible.

```
const liste = document.querySelector("#taches");

liste.addEventListener("click", (event) => {
  // On ne réagit qu'aux clics sur un bouton .supprimer
  if (event.target.matches(".supprimer")) {
    event.target.closest("li").remove();
  }
});
```

Un seul écouteur gère tous les boutons de la liste, **y compris ceux ajoutés dynamiquement** après le chargement. La méthode `matches()` teste si l’élément cliqué correspond à un sélecteur, et `closest()` remonte jusqu’à l’ancêtre voulu. La délégation est la bonne réponse à « comment gérer les clics sur une liste qui change ».

## removeEventListener : nettoyer un écouteur

Pour retirer un écouteur, on utilise `removeEventListener`. Contrainte majeure : il faut lui passer **exactement la même fonction** qu’à l’ajout. Une fonction anonyme est donc impossible à retirer — il faut une référence nommée.

```
function gererClic() {
  console.log("Clic !");
}

bouton.addEventListener("click", gererClic);

// Plus tard : on retire (même référence obligatoire)
bouton.removeEventListener("click", gererClic);
```

L’option `{ once: true }` est un raccourci pratique quand l’écouteur ne doit se déclencher qu’une seule fois : il se retire automatiquement après le premier déclenchement.

```
bouton.addEventListener("click", () => {
  console.log("Ne s'exécute qu'une fois");
}, { once: true });
```

Nettoyer les écouteurs devenus inutiles évite les fuites de mémoire, notamment dans les applications à navigation dynamique où l’on crée et détruit beaucoup d’éléments.

## À retenir

`addEventListener(type, callback)` est la porte d’entrée de toute interactivité : elle écoute un événement et exécute une fonction qui reçoit l’objet `event`. Retenez `event.target` (l’élément déclencheur) face à `event.currentTarget` (celui qui écoute), la remontée par _bubbling_ qui permet la délégation, et les deux garde-fous `preventDefault` (annuler le comportement du navigateur) et `stopPropagation` (stopper la remontée). Privilégiez la délégation pour les listes dynamiques et pensez à retirer les écouteurs devenus inutiles avec `removeEventListener` ou l’option `{ once: true }`.

## À lire ensuite

-   [Manipuler le DOM en JavaScript](https://coder-studio.com/tutoriels/manipuler-dom-javascript/)
-   [L’API Fetch en JavaScript : requêtes HTTP modernes](https://coder-studio.com/tutoriels/fetch-api-javascript/)
-   [localStorage et sessionStorage en JavaScript](https://coder-studio.com/tutoriels/localstorage-javascript/)
