Les Événements en JavaScript : addEventListener

click, input, submit, délégation, propagation — gérer les interactions utilisateur

10
Sections
25+
Exemples
Vanilla JS
Pas de framework

SECTION 01

addEventListener : la base

🎯 Écouter un événement

// Syntaxe : element.addEventListener(événement, callback)

const btn = document.querySelector(« #btn »);

btn.addEventListener(« click », () => );

// Plusieurs listeners sur le même élément (pas de conflit)
btn.addEventListener(« click », logClick);
btn.addEventListener(« click », sendAnalytics);
btn.addEventListener(« mouseenter », showTooltip);

N'utilise jamais les attributs HTML inline (onclick= »… ») ou les propriétés (el.onclick = …). addEventListener est la seule méthode qui permet plusieurs listeners et qui se retire proprement.

SECTION 02

L'objet event

Le callback reçoit un objet event (e) avec toutes les informations sur l'événement :

btn.addEventListener(« click », (e) => );

Propriété Rôle
e.target L'élément cliqué (peut être un enfant)
e.currentTarget L'élément qui porte le listener
e.preventDefault() Empêche l'action par défaut (lien, submit…)
e.stopPropagation() Empêche le bubbling vers le parent
e.key Touche pressée (événements clavier)
e.clientX / e.clientY Position de la souris dans le viewport

SECTION 03

Événements souris

Événement Déclenché quand
click Clic (souris ou clavier sur un bouton focusé)
dblclick Double clic
mousedown / mouseup Bouton enfoncé / relâché
mouseenter / mouseleave Souris entre / sort de l'élément (pas de bubbling)
mouseover / mouseout Comme enter/leave mais avec bubbling
mousemove Souris bouge sur l'élément (très fréquent)
contextmenu Clic droit
// Exemple : suivre la souris
document.addEventListener(« mousemove », (e) => );

SECTION 04

Événements clavier

Événement Déclenché quand Note
keydown Touche enfoncée ✅ Le plus utilisé
keyup Touche relâchée Utile pour détecter le relâchement
keypress ❌ Obsolète — ne plus utiliser
// Détecter des touches spécifiques
document.addEventListener(« keydown », (e) => );

// Raccourcis clavier (Ctrl+S)
document.addEventListener(« keydown », (e) => );

Utilise e.key (la touche logique : « Enter », « a ») et pas e.keyCode qui est obsolète. Pour les modificateurs : e.ctrlKey, e.shiftKey, e.altKey, e.metaKey (Cmd sur Mac).

SECTION 05

Événements formulaire

Événement Déclenché quand Sur
submit Formulaire soumis La balise

input Valeur change (en temps réel) input, textarea, select
change Valeur change (quand le champ perd le focus) input, textarea, select
focus / blur Champ reçoit / perd le focus Tout élément focusable
// Intercepter le submit d'un formulaire
const form = document.querySelector(« #login-form »);

form.addEventListener(« submit », (e) => );

// Recherche en temps réel
const search = document.querySelector(« #search »);

search.addEventListener(« input », (e) => );

FormData est la façon propre de récupérer toutes les valeurs d'un formulaire. Pas besoin de querySelectorAll sur chaque input. new FormData(form) collecte tout d'un coup.

SECTION 06

Propagation et bubbling

🫧 Le bubbling (remontée)

Quand tu cliques sur un élément, l'événement remonte vers le parent, puis le grand-parent, jusqu'au document. C'est le bubbling.

« parent »>

document.querySelector(« #parent »).addEventListener(« click », () => );

document.querySelector(« #child »).addEventListener(« click », () => );

// Clic sur le bouton → affiche :
// « Bouton cliqué »
// « Parent cliqué » ← le clic REMONTE au parent

// Empêcher la remontée
child.addEventListener(« click », (e) => );

SECTION 07

Délégation d'événements

⚡ Le pattern le plus important

Au lieu de mettre un listener sur chaque élément, tu en mets un seul sur le parent. Grâce au bubbling, le parent intercepte les clics de tous ses enfants.

// ❌ Sans délégation — un listener par bouton (lourd)
document.querySelectorAll(« .card .delete-btn »).forEach(btn => );
// ⚠️ Ne fonctionne pas pour les cartes ajoutées APRÈS

// ✅ Avec délégation — un seul listener sur le parent
document.querySelector(« .cards-container »).addEventListener(« click », (e) => );

Avantages de la délégation : (1) Un seul listener au lieu de N — meilleure performance. (2) Fonctionne pour les éléments ajoutés dynamiquement (pas besoin de ré-attacher). (3) closest() est la clé — il retrouve l'ancêtre qui matche.

🔄 Exemple : liste dynamique
// Le listener est sur le

    , fonctionne même
    // pour les

  • ajoutés après
    const list = document.querySelector(« #todo-list »);

    list.addEventListener(« click », (e) => );

SECTION 08

Supprimer un listener

// Pour retirer un listener, il faut une référence à la MÊME fonction

function handleClick()

btn.addEventListener(« click », handleClick);
btn.removeEventListener(« click », handleClick); // ✅ Même référence

// ❌ NE MARCHE PAS — fonctions anonymes différentes
btn.addEventListener(« click », () => console.log(« A »));
btn.removeEventListener(« click », () => console.log(« A »)); // ❌ Autre ref

// Option — se supprime automatiquement après 1 exécution
btn.addEventListener(« click », handleClick, );

// AbortController — retirer plusieurs listeners d'un coup
const controller = new AbortController();

btn.addEventListener(« click », fn1, );
btn.addEventListener(« mouseenter », fn2, );
input.addEventListener(« input », fn3, );

controller.abort(); // supprime les 3 listeners d'un coup

AbortController est la méthode moderne (2021+) pour gérer le cycle de vie des listeners. Un seul abort() nettoie tout — très utile dans les composants et les SPA.

SECTION 09

Erreurs fréquentes

Erreur Problème Solution
Script chargé avant le DOM querySelector retourne null defer sur le script ou DOMContentLoaded
Appeler la fonction au lieu de la passer addEventListener(« click », fn()) exécute fn immédiatement Passer la référence : fn sans ()
Un listener par item dynamique Ne marche pas pour les éléments ajoutés après Utiliser la délégation
Pas de preventDefault sur submit La page se recharge e.preventDefault() en premier
Vouloir retirer un listener anonyme Impossible sans référence Nommer la fonction ou utiliser AbortController

SECTION 10

Questions fréquentes

Quelle différence entre e.target et e.currentTarget ?
e.target est l'élément qui a déclenché l'événement (celui sur lequel l'utilisateur a cliqué). e.currentTarget est l'élément qui porte le listener. Avec la délégation, e.target peut être un enfant tandis que e.currentTarget est le parent.
Différence entre input et change ?
input se déclenche à chaque modification (chaque frappe, chaque caractère). change se déclenche quand le champ perd le focus et que la valeur a changé. Pour une recherche en temps réel, utilise input. Pour la validation à la fin, utilise change.
Comment éviter que le script s'exécute avant le DOM ?
Ajoute l'attribut defer à ta balise script :
Aller en haut