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.targetL'élément cliqué (peut être un enfant)
e.currentTargetL'é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.keyTouche pressée (événements clavier)
e.clientX / e.clientYPosition de la souris dans le viewport

SECTION 03

Événements souris

ÉvénementDéclenché quand
clickClic (souris ou clavier sur un bouton focusé)
dblclickDouble clic
mousedown / mouseupBouton enfoncé / relâché
mouseenter / mouseleaveSouris entre / sort de l'élément (pas de bubbling)
mouseover / mouseoutComme enter/leave mais avec bubbling
mousemoveSouris bouge sur l'élément (très fréquent)
contextmenuClic droit
// Exemple : suivre la souris
document.addEventListener(« mousemove », (e) => );

SECTION 04

Événements clavier

ÉvénementDéclenché quandNote
keydownTouche enfoncée✅ Le plus utilisé
keyupTouche relâchéeUtile 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énementDéclenché quandSur
submitFormulaire soumisLa balise

inputValeur change (en temps réel)input, textarea, select
changeValeur change (quand le champ perd le focus)input, textarea, select
focus / blurChamp reçoit / perd le focusTout é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

ErreurProblèmeSolution
Script chargé avant le DOMquerySelector retourne nulldefer sur le script ou DOMContentLoaded
Appeler la fonction au lieu de la passeraddEventListener(« click », fn()) exécute fn immédiatementPasser la référence : fn sans ()
Un listener par item dynamiqueNe marche pas pour les éléments ajoutés aprèsUtiliser la délégation
Pas de preventDefault sur submitLa page se rechargee.preventDefault() en premier
Vouloir retirer un listener anonymeImpossible sans référenceNommer 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