Événements JavaScript et pages interactives
DébutantUnité 6 sur 9 de la formation Formation : JavaScript : DOM, événements et code asynchrone
Ce que tu vas apprendre
- Fais réagir une page lorsqu’un événement se produit : ajoute des écouteurs aux éléments, lis les informations fournies par l’objet événement et décide combien de temps chaque écouteur reste actif.
- Ajoute un écouteur d’événements à un élémentUtilise
addEventListenerpour exécuter une fonction chaque fois qu’un clic, un appui sur une touche, une action sur un formulaire ou un événement de page se produit sur un élément. - Lis les informations de l’objet événementUtilise l’objet événement reçu par un écouteur pour savoir ce qui s’est passé et où : son type, sa cible, sa cible courante et les détails propres à l’événement.
- Supprime des écouteurs et contrôle leur exécutionArrête l’écoute lorsqu’un écouteur n’est plus nécessaire, utilise les options
once,signaletpassive, et déclenche tes propres événements personnalisés.
- Ajoute un écouteur d’événements à un élément
- Explique comment un événement descend vers sa cible puis remonte dans la page, annule un comportement intégré du navigateur lorsque tu le remplaces et utilise le bouillonnement pour gérer plusieurs éléments avec un seul écouteur.
- Explique le bouillonnement et la captureDécris les trois phases de propagation d’un événement et prévois l’ordre d’exécution des écouteurs sur des éléments imbriqués.
- Empêche les actions par défaut et arrête la propagationAnnule la réponse intégrée du navigateur à un événement lorsque ton code la remplace, et n’arrête la propagation d’un événement que lorsque c’est vraiment nécessaire.
- Gère plusieurs éléments avec la délégation d’événementsUtilise un seul écouteur sur un ancêtre commun et
event.target.closest()pour gérer les événements provenant de plusieurs éléments enfants, y compris ceux ajoutés ultérieurement.
- Explique le bouillonnement et la capture
- Réagis aux appuis sur les touches, aux changements de focus, aux clics, aux contacts tactiles et au stylet, puis crée une interaction de glissement qui fonctionne avec tous les types de pointeurs.
- Réagis aux appuis sur les touches et aux changements de focusUtilise
keydown,keyupet les événements de focus, choisis entreevent.keyetevent.code, et crée des raccourcis clavier qui ne gênent pas l’utilisateur. - Gère les clics, les contacts tactiles et le stylet avec les événements de pointeurUtilise
clickpour l’activation et les événements de pointeur pour gérer l’appui, le déplacement et le relâchement avec une souris, un doigt ou un stylet ; lis les coordonnées et les boutons, et choisis les événements de survol adaptés. - Crée une interaction de glissement avec des événements de pointeurCombine
pointerdown,pointermoveetpointerupavec la capture du pointeur pour déplacer un élément, assurer son fonctionnement sur écran tactile et proposer un moyen de faire la même chose sans glissement.
- Réagis aux appuis sur les touches et aux changements de focus
- Lis les données saisies par les utilisateurs pendant leur saisie, gère l’envoi des formulaires en JavaScript et vérifie les entrées avec les fonctions de validation du navigateur et tes propres règles, accompagnées de messages d’erreur clairs.
- Lis les champs de formulaire et réagis pendant la saisieLis les champs de texte et de nombres, les cases à cocher, les boutons radio et les listes déroulantes, utilise les événements
inputetchangeau bon moment et recueille les données d’un formulaire entier avecFormData. - Gère l’envoi des formulaires en JavaScriptÉcoute l’événement
submitdu formulaire, empêche le rechargement de la page, lis les données envoyées et identifie ce qui déclenche une soumission. - Utilise la validation intégrée du navigateurDécris des règles avec des attributs HTML, lis le résultat dans l’objet
validity, vérifie les champs depuis le code et mets en forme les champs invalides au bon moment. - Écris une validation personnalisée avec des messages d’erreur clairsAjoute des règles que les attributs HTML ne peuvent pas exprimer, rédige des messages utiles, affiche-les au bon moment et associe-les à leurs champs.
- Lis les champs de formulaire et réagis pendant la saisie
- Crée des éléments interactifs utilisables à la souris, au clavier et avec un lecteur d’écran : privilégie le HTML natif, ajoute des rôles, la prise en charge du clavier et des états lorsque tu crées tes propres composants, et place le focus là où les utilisateurs l’attendent.
- Privilégie les éléments natifs et rends les composants personnalisés accessibles au focusIdentifie ce que les éléments interactifs natifs fournissent d’emblée et ce qu’un composant personnalisé construit à partir d’un
<div>ou d’un<span>doit ajouter : un rôle, la capacité à recevoir le focus, un nom accessible et un indicateur de focus visible. - Ajoute la prise en charge du clavier et la gestion de l’état aux composants personnalisésRends les boutons, boutons à bascule, composants de divulgation, cases à cocher et groupes d’éléments personnalisés utilisables au clavier, et maintiens leur état ARIA en accord avec ce que voient les utilisateurs.
- Place le focus là où les utilisateurs l’attendent lorsque la page changeDéplace le focus volontairement lorsqu’un contenu s’ouvre, se ferme, est supprimé ou affiche des erreurs, et ne le déplace jamais de façon inattendue pendant que les utilisateurs saisissent du texte ou font un choix.
- Privilégie les éléments natifs et rends les composants personnalisés accessibles au focus
Événements JavaScript : cours
1Réagis aux événements avec des écouteurs d’événements
Les pages web réagissent grâce à des fonctions enregistrées pour des événements. La mise en place détermine l’élément et le type d’événement ; chaque occurrence ultérieure fournit un objet événement qui décrit ce qui s’est passé. La lecture de cet objet permet à un écouteur d’agir sur le bon composant, même lorsqu’un clic atteint une icône à l’intérieur de celui-ci. Les références et les options des écouteurs permettent ensuite à une fonctionnalité de garder ses réponses actives exactement le temps nécessaire, et les événements personnalisés permettent à une partie de la page d’en informer une autre.
1.1 Les écouteurs déclenchent du code en réponse aux actions
Une page peut attendre qu’une personne agisse. Un événement signale ce qui s’est passé et un écouteur d’événements est la fonction appelée en réponse. Enregistrer un écouteur prépare cette réponse ; cela n’effectue pas l’action immédiatement.
Ajouter la fonction à l’élément
Sélectionne un élément qui existe déjà, choisis le nom exact de l’événement et passe une fonction :
const button = document.querySelector("#like");
let likes = 0;
button.addEventListener("click", function () {
likes = likes + 1;
button.textContent = "Likes: " + likes;
});
La sélection, la définition de la variable et l’enregistrement s’exécutent lorsque le script s’exécute. Chaque clic ultérieur exécute le corps de la fonction. Après trois clics, le bouton affiche « Likes: 3 ». Garder likes hors de la fonction conserve le total entre les clics ; placer let likes = 0 à l’intérieur le remettrait à zéro à chaque fois.
Passe une référence de fonction, comme showMenu, sans parenthèses. Dans button.addEventListener("click", showMenu()), JavaScript appelle immédiatement showMenu et passe sa valeur de retour comme écouteur. Pour fournir un argument plus tard, place l’appel dans une fonction enveloppante : button.addEventListener("click", () => showMenu("main"));.
Choisir un événement qui se produit réellement
Les noms sont des chaînes sensibles à la casse sans préfixe « on ». Utilise "click", et non "Click" ou "onclick". Un nom inventé est accepté sans erreur, mais le navigateur ne l’émettra pas pour un clic. Parmi les familles courantes figurent les événements de pointeur comme pointerdown et pointerup, les événements clavier comme keydown, les événements de formulaire comme input et submit, et les événements de focus comme focusin. DOMContentLoaded possède sa propre casse exacte.
Configurer le bon élément au bon moment
Un script dans l’en-tête peut s’exécuter avant qu’un bouton existe. La sélection renvoie alors null, et appeler addEventListener sur cette valeur provoque une erreur. Charge un script externe avec defer, place-le après le balisage ou enregistre la mise en place sur l’événement DOMContentLoaded du document. Un élément créé plus tard nécessite une mise en place après sa création ou un écouteur sur un ancêtre.
querySelectorAll renvoie une NodeList, et non une seule cible d’événement. Enregistre les écouteurs sur ses éléments :
document.querySelectorAll(".tab").forEach((tab) => {
tab.addEventListener("click", selectTab);
});
Faire coexister les écouteurs
| Méthode | Effet de l’enregistrement |
|---|---|
addEventListener("click", fn) | Ajoute un écouteur à côté des autres et accepte des options. |
button.onclick = fn | Remplace l’unique gestionnaire de la propriété ; affecte null pour le supprimer. |
Un attribut HTML onclick | Place du JavaScript dans le balisage. |
Les écouteurs ayant le même réglage de capture s’exécutent dans leur ordre d’enregistrement. Sur la cible de l’événement, les écouteurs en phase de capture s’exécutent avant les autres. Ajouter de nouveau le même objet fonction avec le même type et le même réglage de capture n’en ajoute pas un second exemplaire.
Points clés
- Passe la fonction elle-même ; utilise une fonction enveloppante lorsque l’appel ultérieur a besoin d’arguments.
- Les noms d’événements exigent une orthographe et une casse exactes.
- Un élément doit exister lorsque son écouteur est enregistré.
- Parcours une NodeList avec une boucle pour ajouter des écouteurs à ses éléments.
addEventListenerpermet d’ajouter plusieurs écouteurs ; une propriété de gestionnaire n’en contient qu’un.
1.2 Identifie où un événement a commencé
Le navigateur passe un objet événement à ton écouteur. Ses propriétés expliquent l’événement qui a déclenché cet appel précis. Nomme le paramètre event ou e ; le choix de son nom t’appartient.
button.addEventListener("click", (event) => {
console.log(event.type);
console.log(event.currentTarget);
});
Ce code affiche "click" et le bouton dans la console pendant l’appel de l’écouteur. Afficher l’objet entier peut t’aider à découvrir ses autres propriétés.
Distinguer l’origine de l’écouteur
Imagine un bouton contenant une image :
<button id="save" data-id="7">
<img src="disk.svg" alt=""> Save
</button>
| Propriété | Signification | Lors d’un clic sur l’image |
|---|---|---|
event.target | L’endroit où l’événement a commencé | L’image |
event.currentTarget | L’élément auquel l’écouteur en cours a été ajouté | Le bouton, pour un écouteur sur le bouton |
Un clic sur le texte « Save » fait aussi du bouton la cible. Le texte fait partie du bouton ; il ne devient pas un élément cible distinct.
Cette différence compte pour lire les données. L’image n’a pas le data-id du bouton : event.target.dataset.id vaut donc undefined lors d’un clic sur l’image. Un écouteur ajouté directement au bouton peut lire event.currentTarget.dataset.id. Un écouteur sur un conteneur plus grand peut trouver le bouton recherché avec event.target.closest("button") et vérifier qu’un élément correspondant existe.
Lire les détails de cet événement
Chaque événement possède un type, un target et un currentTarget. Le booléen bubbles indique s’il remonte à travers les ancêtres. cancelable indique si le code peut annuler son action par défaut, et defaultPrevented indique si cette annulation a eu lieu. timeStamp indique l’instant de création de l’événement en millisecondes par rapport à l’origine temporelle de la page.
Les différentes familles d’événements ajoutent des détails utiles. Un click moderne fournit un PointerEvent, qui hérite des propriétés d’événement de souris comme clientX, clientY et button. Un KeyboardEvent ajoute key, code et des indicateurs de touches de modification. Un écouteur input peut utiliser event.target.value pour lire le nouveau texte du champ.
Pour un écouteur sur une galerie, event.target.tagName peut valoir "IMG" lors d’un clic sur une photo ou "DIV" lors d’un clic dans l’espace entre les photos. Gère le cas effectivement indiqué. Ne suppose pas que tous les événements dans un conteneur proviennent du même type d’enfant.
Utiliser la valeur pendant l’exécution de l’écouteur
Dans un écouteur écrit avec une fonction classique, this est égal à event.currentTarget. Une fonction fléchée prend this dans le code qui l’entoure ; elle ne prend pas l’élément comme this. L’utilisation de event.currentTarget fonctionne avec les deux formes de fonction.
Après le déclenchement, currentTarget est remis à null. Une console peut afficher cette valeur ultérieure lorsque tu développes un événement affiché auparavant. Affiche event.currentTarget directement dans l’écouteur pour examiner l’élément pendant l’appel.
Points clés
targetindique l’origine de l’événement ;currentTargetindique l’élément de l’écouteur en cours.- Lis les données sur l’élément qui les possède réellement.
- Les familles d’événements ajoutent des propriétés comme les coordonnées, les valeurs des touches et les touches de modification.
currentTargetest disponible pendant l’exécution de l’écouteur et devientnullensuite.
1.3 Contrôle la durée de vie d’un écouteur
Un écouteur doit rester actif tant que sa fonctionnalité en a besoin. Pour une interaction temporaire au clavier, garde la référence de la fonction afin de pouvoir la supprimer lorsque l’interaction se termine.
Supprimer la même fonction
function onKey(event) {
console.log(event.key);
}
document.addEventListener("keydown", onKey);
// When the feature closes:
document.removeEventListener("keydown", onKey);
La suppression recherche le même type d’événement, le même objet fonction et le même réglage de capture. Une fonction anonyme peut aussi être supprimée lorsque sa référence est enregistrée, comme dans const handler = () => save();. Écrire un nouveau () => save() dans l’appel de suppression crée une fonction différente, même si le code semble identique.
Choisir les options d’enregistrement
| Option | Effet |
|---|---|
once: true | Supprime cet écouteur après son premier appel. |
signal: controller.signal | Supprime l’écouteur lorsque ce contrôleur est annulé. |
capture: true | Écoute pendant la phase de capture. |
passive: true | Indique que l’écouteur n’annulera pas l’action par défaut. |
Une bannière de bienvenue à affichage unique peut utiliser { once: true }. Une fonctionnalité avec plusieurs écouteurs peut leur donner un même signal :
const controller = new AbortController();
window.addEventListener("pointermove", moveCursor, {
signal: controller.signal
});
window.addEventListener("keydown", onKey, {
signal: controller.signal
});
// Close the feature:
controller.abort();
L’annulation supprime les deux enregistrements. Un contrôleur annulé ne peut pas être réinitialisé ; crée un nouveau contrôleur pour une nouvelle période d’utilisation. Pour une suppression avec removeEventListener, répète capture: true si ce réglage a été utilisé lors de l’enregistrement. once, signal et passive ne font pas partie des critères de correspondance pour la suppression.
L’appel de preventDefault() par un écouteur passif est ignoré. Les navigateurs rendent couramment passifs par défaut certains écouteurs liés au défilement sur les cibles au niveau du document, notamment pour wheel, touchstart et touchmove ; utilise explicitement { passive: false } dans ces cas lorsqu’une annulation est nécessaire.
Éviter l’accumulation de fonctions de rappel
Si chaque clic sur « Start » ajoute un nouvel écouteur anonyme au plateau, deux démarrages font qu’un clic sur le plateau exécute deux fonctions de rappel. Installe l’écouteur du plateau une seule fois, réutilise le même objet fonction ou annule le groupe précédent avant de le remplacer. Des fonctions de rappel once distinctes peuvent quand même s’accumuler avant leur exécution.
Détacher un élément conserve ses écouteurs. Ils fonctionnent s’il est réinséré, et dispatchEvent() peut les atteindre lorsqu’il est détaché. Le ramasse-miettes peut récupérer l’élément lorsque celui-ci et ses écouteurs ne sont plus accessibles. Un écouteur sur window ou document reste en place jusqu’à sa suppression explicite.
Envoyer un événement personnalisé
const event = new CustomEvent("cart:add", {
detail: { id: 42 },
bubbles: true
});
item.dispatchEvent(event);
Les écouteurs lisent event.detail.id. Le déclenchement appelle immédiatement les écouteurs, avant de rendre la main. bubbles: true permet aussi aux ancêtres de recevoir l’événement. Un événement envoyé avec dispatchEvent() a isTrusted égal à false ; les événements déclenchés par le navigateur peuvent être considérés comme fiables même lorsqu’une API comme focus() les a provoqués.
Points clés
- La suppression recherche le même type, la même identité de fonction et le même réglage de capture.
oncemet fin à un enregistrement après un appel ; l’annulation d’un signal met fin aux enregistrements qui lui sont associés.- Un écouteur passif ne peut pas annuler une action par défaut.
- De nouvelles fonctions de rappel ajoutées à chaque mise en place peuvent s’accumuler.
- Détacher un élément conserve ses écouteurs.
- Les événements personnalisés transportent des données dans
detailet sont déclenchés de façon synchrone.
2Suis la propagation des événements dans la page
Des éléments imbriqués partagent le trajet d’un événement. Un clic peut passer par un conteneur avant d’atteindre sa cible, puis y repasser pendant le bouillonnement, ce qui permet à un seul écouteur de gérer une liste qui change. Suivre ce trajet aide à comprendre pourquoi l’action d’un enfant déclenche aussi celle d’un parent. Distingue l’annulation du comportement du navigateur du contrôle de la propagation, puis utilise l’origine de l’événement pour choisir les actions qu’un écouteur partagé doit gérer.
2.1 Le trajet d’un événement dans des éléments imbriqués
Un clic dans un bouton peut aussi être reçu par les ancêtres du bouton. La propagation est le trajet de l’événement dans l’arbre du document. Suivre ce trajet permet de comprendre aussi bien les écouteurs partagés utiles que les actions supplémentaires surprenantes.
Suivre trois phases
- Capture : l’événement descend depuis
windowà travers les ancêtres vers la cible. - Cible : les écouteurs s’exécutent sur l’élément où l’événement a commencé.
- Bouillonnement : un événement qui remonte par bouillonnement traverse les ancêtres jusqu’à
window.
La propriété eventPhase indique 1 pour la capture, 2 sur la cible et 3 pour le bouillonnement. Un écouteur enregistré sans options s’exécute sur la cible ou pendant la remontée. Un écouteur avec { capture: true } s’exécute pendant la descente, y compris sur la cible s’il y est enregistré.
Suivre un clic concret
<div id="outer">
<div id="inner">
<button>Go</button>
</div>
</div>
Supposons que le bouton et chaque div aient des écouteurs de clic ordinaires qui affichent leur nom. Un clic sur « Go » affiche « button », « inner », puis « outer ». Un clic sur une zone vide de inner affiche « inner », puis « outer » ; le bouton ne se trouve pas sur le trajet de cet événement.
Ajoute maintenant un écouteur en phase de capture à outer. Un clic sur le bouton affiche d’abord « outer (capture) », puis « button », « inner » et « outer » depuis les écouteurs ordinaires. L’écouteur en phase de capture reçoit le clic avant les descendants. Après outer, l’événement peut continuer à travers body, html, document et window si des écouteurs y sont enregistrés.
Il s’agit d’un seul événement, pas d’un nouveau clic créé sur chaque ancêtre. target reste le bouton tout au long du trajet. currentTarget change à mesure que chaque écouteur s’exécute. Dans l’écouteur de l’élément extérieur, lire target indique toujours le bouton d’origine.
Vérifier quels événements remontent par bouillonnement
| Remontent par bouillonnement | Ne remontent pas par bouillonnement |
|---|---|
click, input, change, submit | invalid |
keydown, pointerdown | focus, blur |
focusin, focusout | pointerenter, pointerleave |
pointerover, pointerout | mouseenter, mouseleave |
La propriété bubbles de l’événement indique s’il possède une phase de bouillonnement. Les événements sans bouillonnement peuvent quand même être observés par un écouteur en phase de capture sur un ancêtre. Pour gérer les changements de focus au moyen d’un écouteur ordinaire sur un conteneur, choisis focusin ou focusout.
Expliquer un bogue lié à des actions imbriquées
Une fiche produit ouvre une vue détaillée lorsqu’on clique dessus. Son bouton « Supprimer » supprime le produit. Un clic sur ce bouton supprime d’abord le produit, puis atteint l’écouteur de la fiche et ouvre la vue détaillée. Le trajet de l’événement explique pourquoi les deux fonctions de rappel s’exécutent.
La fiche peut ignorer les clics de suppression avec if (event.target.closest(".remove")) return;. Le bouton peut aussi arrêter la propagation. Filtrer au niveau de la fiche conserve l’événement pour les autres ancêtres qui peuvent en avoir besoin.
Points clés
- La propagation suit les phases de capture, cible puis de bouillonnement pour les événements qui remontent.
- Les écouteurs ordinaires sur les ancêtres reçoivent les clics des descendants pendant la remontée.
targetreste inchangé tandis quecurrentTargetchange.- Utilise un événement de focus qui remonte par bouillonnement ou la capture pour observer le focus depuis un ancêtre.
2.2 Annuler une action ou arrêter la propagation
Un écouteur peut modifier ce qui se passe après un événement ou le trajet que suit l’événement. Ce sont deux décisions distinctes. Un événement sur un lien peut continuer à remonter par bouillonnement même après l’annulation de la navigation.
Remplacer une action du navigateur
Une action par défaut est un comportement fourni par le navigateur : suivre un lien, envoyer un formulaire, changer l’état d’une case à cocher, insérer du texte, faire défiler avec Espace ou déplacer le focus avec Tabulation. Utilise preventDefault() lorsque ton code remplace cette action :
help.addEventListener("click", (event) => {
event.preventDefault();
openHelpPanel();
});
Pour un lien vers /help, ce code ouvre le panneau sans naviguer vers une autre page. Le lien donne toujours accès à sa destination lorsque JavaScript ne s’exécute pas.
Seuls les événements annulables peuvent être annulés. Examine event.cancelable ; defaultPrevented indique si l’annulation a réussi. input se produit après le changement de valeur et n’est pas annulable. Y appeler preventDefault() ne supprime pas le texte inséré. Un événement beforeinput annulable est le bon endroit pour intercepter une modification ; annuler un événement keydown approprié peut empêcher l’effet par défaut de cette touche.
Contrôler la propagation séparément
| Méthode | Arrête l’action par défaut du navigateur ? | Arrête les écouteurs suivants ? |
|---|---|---|
preventDefault() | Oui, si l’événement est annulable et l’écouteur non passif | Non |
stopPropagation() | Non | Arrête la propagation vers les autres éléments ; les écouteurs de cet élément s’exécutent quand même |
stopImmediatePropagation() | Non | Arrête aussi les écouteurs restants sur cet élément |
Un lien dont l’écouteur ne fait qu’arrêter la propagation est quand même suivi. Annuler uniquement la navigation permet toujours à un écouteur de clic sur le document de recevoir l’événement. Renvoyer false depuis une fonction de rappel ajoutée avec addEventListener ne fait ni l’un ni l’autre. Une propriété ou un attribut en ligne de gestionnaire peut annuler l’action par défaut en renvoyant false, mais cela n’arrête toujours pas la propagation.
Préserver les comportements partagés
Un ancêtre peut fermer un menu ou compter les interactions. Arrêter la propagation cache l’événement à ce code. L’ancêtre peut souvent examiner target ou defaultPrevented à la place.
Par exemple, un menu ne se ferme que lorsqu’un clic a lieu en dehors du menu et de son élément déclencheur :
document.addEventListener("click", (event) => {
if (!menu.contains(event.target) &&
!menuButton.contains(event.target)) {
menu.hidden = true;
}
});
contains() inclut l’élément lui-même et ses descendants. Il est important de vérifier l’élément déclencheur, car le clic qui ouvre le menu remonte aussi par bouillonnement jusqu’au document. Sans ce second test, le menu qui vient de s’ouvrir se fermerait immédiatement.
N’annuler qu’une action prise en charge
Dans un écouteur de touche, vérifie la touche avant d’annuler son action. Annuler chaque touche bloque la saisie ordinaire et peut empêcher Tabulation de déplacer le focus. Dans un écouteur passif, l’annulation est entièrement ignorée.
Points clés
preventDefault()annule une action par défaut qui peut l’être tout en préservant la propagation.stopPropagation()arrête la propagation, pas l’action par défaut.stopImmediatePropagation()ignore aussi les écouteurs restants sur l’élément courant.inputintervient trop tard pour annuler une modification.- Les tests de clic à l’extérieur doivent inclure l’élément contextuel et son élément déclencheur.
- N’annule que les actions précises du clavier que ton code prend en charge.
2.3 Un seul écouteur pour une liste qui change
La délégation d’événements place un écouteur sur un ancêtre stable et utilise l’origine de l’événement pour choisir une action. Elle est utile lorsqu’une liste comporte de nombreux éléments ou lorsque le code en crée de nouveaux après la mise en place.
Trouver le composant recherché
Un clic qui remonte par bouillonnement atteint la liste quel que soit le descendant sur lequel l’utilisateur a cliqué. Pars de event.target, trouve le composant correspondant le plus proche et ignore les clics sans rapport :
const list = document.querySelector("#todos");
list.addEventListener("click", (event) => {
const button = event.target.closest(".remove");
if (!button || !list.contains(button)) return;
const item = button.closest("li");
console.log("Removing item " + item.dataset.id);
item.remove();
});
La liste contient des éléments comme <li data-id="7">Buy milk <button class="remove">Remove</button></li>. L’écouteur appartient à la liste : un nouvel élément avec le même balisage fonctionne donc dès son insertion.
Suis un clic sur une icône dans le code. La cible est l’icône, closest(".remove") trouve son bouton et button.closest("li") trouve l’élément de liste. Son data-id identifie l’élément dans le message. Enfin, remove() modifie la page.
Conserver les deux vérifications
| Test | Pourquoi il est utile |
|---|---|
!button | Un clic dans un espace vide de la liste ou sur le texte ordinaire d’un élément peut ne trouver aucun bouton de suppression. |
!list.contains(button) | closest() peut remonter au-delà de la liste et trouver un ancêtre extérieur correspondant. |
Tester seulement event.target.matches(".remove") ne prend pas en compte les clics sur l’icône, car l’icône elle-même ne correspond pas au sélecteur. closest() vérifie la cible et remonte ses ancêtres. Dans un écouteur délégué, currentTarget est la liste ; il ne devient pas le bouton trouvé.
Diriger plusieurs actions
Les attributs de données permettent à un écouteur de barre d’outils de choisir parmi des actions connues :
const actions = { bold: makeBold, italic: makeItalic,
clear: clearText };
toolbar.addEventListener("click", (event) => {
const button = event.target.closest("button[data-action]");
if (!button || !toolbar.contains(button)) return;
const action = actions[button.dataset.action];
if (typeof action === "function") action();
});
Un bouton avec data-action="clear" sélectionne clearText. La vérification de la fonction gère une action inconnue sans tenter d’appeler undefined.
Choisir un événement adapté
La délégation fonctionne avec d’autres événements qui remontent par bouillonnement, pas seulement les clics. Un seul écouteur input sur un formulaire peut passer event.target à une fonction de vérification des champs. Pour déléguer les changements de focus, utilise focusin ou focusout ; les événements ordinaires focus et blur ne remontent pas. Pour les changements de survol, utilise les événements over/out qui remontent lorsque la délégation est nécessaire.
Un appel à stopPropagation() sur un descendant peut empêcher un événement d’atteindre le conteneur. Si un écouteur délégué semble inactif, vérifie le type d’événement, la cible, la correspondance avec le sélecteur et si un élément situé sous le conteneur a arrêté la propagation.
Points clés
- Ajoute l’écouteur à un ancêtre qui reste en place lorsque ses enfants changent.
closest()trouve un composant même lorsqu’on clique sur une icône imbriquée.- Ignore les absences de correspondance et les éléments correspondants situés hors du conteneur.
- La délégation inclut automatiquement les enfants correspondants ajoutés ultérieurement.
- Les attributs de données peuvent diriger un écouteur partagé vers des actions connues.
- La délégation nécessite un événement qui atteint l’ancêtre.
3Gère les entrées au clavier et au pointeur
Une interaction peut provenir du clavier, d’une souris, d’un doigt ou d’un stylet. L’événement choisi détermine si tu reçois une activation, une valeur de texte modifiée ou le mouvement d’un pointeur particulier. Les repères de coordonnées et les positions de départ mémorisées rendent le glissement prévisible. Le focus et les autres commandes possibles permettent d’utiliser la même page au clavier ou sans pouvoir effectuer un geste de glissement.
3.1 Touches, texte et focus
Les entrées au clavier vont à l’élément qui a le focus, accessible sous document.activeElement, puis remontent par bouillonnement. Un écouteur sur le document peut donc recevoir les touches depuis les champs comme depuis les autres composants. Cette portée rend les raccourcis clavier utiles, mais signifie aussi qu’ils peuvent interrompre la saisie.
Choisir la propriété selon son sens
| Propriété | Indique | Exemple |
|---|---|---|
key | La valeur produite, compte tenu de la disposition et des touches de modification | "a", "A", "Enter", " " |
code | La position physique de la touche | "KeyA", "Enter", "Space" |
Sur un clavier AZERTY, la touche à l’emplacement marqué Q sur un clavier américain produit key "a" et code "KeyQ". Utilise key pour le sens, comme Échap pour fermer ou une lettre pour un raccourci. Utilise code pour les positions fixes, comme les touches de déplacement dans un jeu. Le key de la barre d’espace est un seul espace, pas "Space".
keydown se déclenche à l’appui initial et peut se répéter tant que la touche reste enfoncée. Lors des appels répétés, event.repeat === true. keyup se déclenche au relâchement. Utilise keydown à la place de l’événement obsolète keypress.
Gérer un raccourci précisément
document.addEventListener("keydown", (event) => {
if ((event.ctrlKey || event.metaKey) &&
event.key.toLowerCase() === "s") {
event.preventDefault();
saveDraft();
}
});
Ce code gère Ctrl+S et Commande+S. La conversion en minuscules permet aussi d’accepter "S". L’annulation ne remplace l’action d’enregistrement de la page du navigateur que pour le raccourci correspondant. Parmi les autres indicateurs de touches de modification figurent shiftKey et altKey.
Pour un raccourci à une seule lettre actif sur toute la page, ignore les contextes de saisie avant d’agir :
if (event.target.matches("input, textarea, select") ||
event.target.isContentEditable) return;
if (event.repeat) return;
La première vérification protège la saisie de texte. La seconde fait exécuter une action une seule fois par appui physique. N’annule pas Tabulation dans toute la page : c’est ainsi que les utilisateurs du clavier passent à la suite.
Écouter le texte après sa modification
Pour une touche ordinaire produisant un caractère affichable, la séquence est keydown, beforeinput, input, puis keyup. Lire value dans keydown donne la valeur avant l’insertion de ce caractère. Utilise input pour un aperçu du texte ou un compteur de caractères. Cet événement prend aussi en compte les modifications comme le collage et la dictée, qui ne nécessitent pas d’appui correspondant sur une touche.
Observer les changements de focus
focus et blur signalent la prise et la perte du focus sans remonter par bouillonnement. focusin et focusout remontent : un formulaire peut donc observer ses champs avec un seul écouteur. relatedTarget indique l’autre élément concerné par le changement, ou null s’il n’y en a pas.
password.addEventListener("focus", () => {
hint.hidden = false;
});
password.addEventListener("blur", () => {
hint.hidden = true;
});
L’indication est disponible lorsque le champ reçoit le focus, notamment avec Tabulation. Appeler element.focus() déplace le focus depuis le code ; la prochaine entrée au clavier va alors à cet élément.
Points clés
- Utilise
keypour le sens de la valeur produite etcodepour la position physique. - Protège les raccourcis à une lettre actifs sur toute la page contre les contextes de saisie et les répétitions indésirables.
- Utilise
inputpour réagir aux modifications de texte, y compris au collage. focusinetfocusoutremontent par bouillonnement ;focusetblurne remontent pas.relatedTargetindique l’autre destination ou origine du focus.
3.2 Activation et mouvement du pointeur
Une personne peut utiliser une souris, un doigt, un stylet ou un clavier. Choisis un événement selon l’interaction souhaitée. click exprime une activation ; les événements de pointeur décrivent l’appui, le mouvement et le relâchement.
Garder les actions accessibles au clavier
Un bouton natif émet click lorsqu’il est activé avec Entrée ou Espace. Un lien qui a le focus fait de même avec Entrée. Relier une action uniquement à pointerdown ou mousedown ne prend pas en compte ces activations au clavier. Utilise click pour les actions comme l’ouverture d’un panneau ; utilise pointerdown lorsque le travail doit commencer dès l’appui, comme pour un glissement.
Un clic au pointeur suit un appui et un relâchement. Lorsqu’ils ont lieu sur des éléments différents, le clic peut avoir pour cible leur ancêtre commun le plus proche. dblclick suit deux clics rapides ; event.detail compte les clics rapides successifs. auxclick gère les clics non principaux. contextmenu peut provenir d’un clic secondaire, d’un appui tactile long ou d’une commande de menu au clavier.
Utiliser une seule famille d’événements de pointeur
pointerdown, pointermove, pointerup et pointercancel couvrent la souris, le tactile et le stylet. pointerType indique l’appareil par "mouse", "touch" ou "pen" ; pointerId distingue les pointeurs actifs, y compris deux doigts.
Les anciennes familles d’événements de souris et tactiles existent toujours. Les navigateurs peuvent émettre des événements de souris de compatibilité après les événements de pointeur. Enregistrer à la fois pointerdown et mousedown pour la même action peut donc l’exécuter deux fois.
Adapter les coordonnées au besoin
| Coordonnées | Origine |
|---|---|
clientX, clientY | Coin supérieur gauche de la zone d’affichage visible |
pageX, pageY | Coin supérieur gauche du document, défilement compris |
offsetX, offsetY | Bord de la zone de remplissage de l’élément cible |
Lorsque le document a défilé de 300 px vers le bas et qu’un clic a lieu à 100 px sous le haut de la zone d’affichage, clientY vaut 100 et pageY vaut 400. Garde les deux positions dans le même repère de coordonnées pour calculer le mouvement. Si la cible imbriquée change, l’origine des coordonnées de décalage peut aussi changer.
button indique quel bouton a changé d’état lors d’un événement d’appui ou de relâchement : 0 pour le principal, 1 pour celui du milieu, 2 pour le secondaire. buttons indique la combinaison actuellement enfoncée : le bouton principal contribue pour 1, le secondaire pour 2 et celui du milieu pour 4. Ainsi, buttons === 3 signifie que les boutons principal et secondaire sont enfoncés ; cela ne signifie pas que le bouton du milieu a changé d’état.
Choisir le comportement de survol pour un composant entier
Les événements over/out remontent par bouillonnement et peuvent se déclencher lorsque le pointeur franchit les frontières des éléments enfants. Les événements enter/leave ne remontent pas et décrivent l’entrée dans l’élément entier ou sa sortie, enfants compris. Une infobulle peut éviter de clignoter au passage des frontières des enfants avec pointerenter et pointerleave.
Les utilisateurs d’écrans tactiles et de claviers ne survolent pas les éléments. Propose aussi les informations essentielles au clic ou à la prise de focus. Pour un effet de survol visuel sans comportement supplémentaire, le sélecteur CSS :hover est plus simple qu’un écouteur.
Points clés
- Utilise
clickpour l’activation, y compris l’activation native au clavier. - Les événements de pointeur couvrent la souris, le tactile et le stylet dans une seule famille.
- Choisis des coordonnées dans le même repère pour les calculs.
buttonindique un changement ;buttonsindique la combinaison enfoncée.- Les événements enter/leave considèrent un élément et ses enfants comme un tout.
- Les informations essentielles doivent être accessibles autrement que par le survol.
3.3 Un glissement qui continue à suivre le pointeur
Un glissement nécessite de conserver des informations entre plusieurs événements. Stocke les coordonnées de départ du pointeur et la position de départ de l’élément. Chaque mouvement applique ensuite la différence depuis ce point de départ, afin que l’élément ne saute pas pour placer son coin sous le pointeur.
Calculer le déplacement
Une boîte commence à left: 100px; top: 50px. Le pointeur part des coordonnées 220, 140 dans la zone d’affichage et se déplace jusqu’à 260, 125. Le déplacement horizontal est de 40 px ; le déplacement vertical est de −15 px. En ajoutant ces déplacements à la position de départ de la boîte, on obtient left: 140px; top: 35px.
Utilise des coordonnées dans la zone d’affichage cohérentes pour les deux relevés du pointeur. Le calcul général est la position de départ de l’élément plus le déplacement du pointeur. N’ajoute pas chaque déplacement complet à la position déjà mise à jour de la boîte, car cela compterait à nouveau les mouvements précédents.
Mémoriser et capturer un pointeur
Pour une boîte sans marge, positionnée de façon absolue dans un conteneur positionné de façon relative :
let start = null;
box.addEventListener("pointerdown", (event) => {
if (start || event.button !== 0) return;
start = { id: event.pointerId, x: event.clientX,
y: event.clientY, left: box.offsetLeft,
top: box.offsetTop };
box.setPointerCapture(event.pointerId);
});
box.addEventListener("pointermove", (event) => {
if (!start || event.pointerId !== start.id) return;
box.style.left = start.left +
(event.clientX - start.x) + "px";
box.style.top = start.top +
(event.clientY - start.y) + "px";
});
function endDrag(event) {
if (start && event.pointerId === start.id) start = null;
}
box.addEventListener("pointerup", endDrag);
box.addEventListener("pointercancel", endDrag);
L’identifiant stocké permet d’ignorer les mouvements et le relâchement d’un second pointeur. offsetLeft et offsetTop fournissent les positions de départ sous forme de nombres ; les styles nécessitent le suffixe "px".
La capture du pointeur maintient les événements suivants de ce pointeur dirigés vers la boîte, même lorsque le pointeur sort de celle-ci. Le navigateur libère la capture après le relâchement ou l’annulation du pointeur. releasePointerCapture(id) peut la libérer plus tôt.
Gérer la reprise en main par le navigateur
Un geste tactile peut devenir un défilement de la page ou un zoom, ce qui provoque pointercancel. Termine aussi le glissement à ce moment-là, comme pour pointerup ; sinon, un état périmé peut continuer à déplacer la boîte plus tard. Applique touch-action: none à la surface de glissement avant l’interaction pour réserver ce geste. Limite cette règle à cette surface afin que le reste de la page puisse défiler.
Utilise user-select: none sur la surface déplaçable pour éviter de sélectionner du texte. Définis draggable="false" sur ses images pour empêcher le comportement natif de glissement d’image.
Proposer un autre moyen de déplacer
Prévois le déplacement au clavier pour un composant qui a le focus et des boutons de déplacement sur lesquels cliquer ou appuyer. Les touches fléchées seules ne fournissent pas d’alternative à pointeur unique au glissement. Le critère de succès 2.5.7 des WCAG 2.2 exige une telle alternative, sauf si le glissement est essentiel ou relève d’un comportement du navigateur non modifié. Des boutons de déplacement natifs peuvent convenir aux utilisateurs du clavier comme du pointeur.
L’API HTML Drag and Drop, distincte, utilise dragstart, dragover et drop pour transférer des données, comme des fichiers. Sa séquence d’événements diffère de ce changement de position fondé sur le pointeur.
Points clés
- Calcule chaque position à partir du point de départ mémorisé et du déplacement du pointeur.
- Capture le pointeur actif et suis son identifiant.
- Termine le glissement aussi bien à
pointerupqu’àpointercancel. - Applique les règles tactiles et de sélection à la surface de glissement.
- Prévois un accès au clavier et une alternative utilisable par clic ou contact tactile.
4Gère les formulaires et valide les entrées avant l’envoi
Les formulaires combinent plusieurs types d’état : texte, valeurs numériques, choix cochés et noms répétés. Lis ces valeurs lors du bon événement, puis gère la soumission du formulaire comme une seule action. Les contraintes HTML fournissent des règles de validation courantes, tandis que JavaScript ajoute des relations entre les champs et des indications plus claires. Un formulaire utile conserve le travail de l’utilisateur, explique chaque correction et place le focus là où la prochaine modification doit être faite.
4.1 Lis les valeurs lorsqu’elles changent
Les composants de formulaire exposent différents types d’état. La propriété value d’un champ de texte est une chaîne ; la propriété checked d’une case à cocher est un booléen. Lire la bonne propriété est la première étape pour obtenir des calculs et des aperçus fiables.
Convertir les nombres volontairement
Même <input type="number"> possède une value qui est une chaîne. Avec le texte "3", ajouter 1 donne "31". Number(input.value) + 1 donne 4. Un champ numérique expose aussi valueAsNumber.
Une entrée vide nécessite une décision particulière. Number("") donne 0, ce qui peut faire passer une quantité manquante pour un vrai zéro. Vérifie d’abord input.value === "", ou utilise valueAsNumber, qui donne NaN pour un champ numérique vide. Teste ce résultat avec Number.isNaN().
Lire l’état sélectionné
| Composant | Propriété à lire |
|---|---|
| Champ de texte, zone de texte, liste déroulante | value |
| Champ numérique utilisé dans un calcul | valueAsNumber, ou conversion d’une value non vide |
| Case à cocher | checked pour l’état coché ou non |
Groupe de boutons radio nommé size | form.elements.size.value pour la valeur sélectionnée |
La propriété value d’une case à cocher est le texte configuré pour son envoi, ou "on" si aucun n’est fourni. Elle n’indique pas si la case est cochée. Une liste déroulante indique la valeur de l’option choisie. Pour trouver l’élément radio sélectionné lui-même, recherche input[name="size"]:checked.
Adapter l’événement à la mise à jour
input signale les modifications de l’utilisateur au fur et à mesure, y compris la saisie et le collage. change signale un choix validé : après la perte de focus d’un champ de texte modifié, ou immédiatement lorsqu’une case à cocher, un bouton radio ou une liste déroulante change.
message.addEventListener("input", () => {
counter.textContent = 280 - message.value.length +
" characters left";
});
Après « Hello », cinq caractères ont été utilisés et le compteur affiche « 275 characters left ». Un écouteur keydown s’exécuterait avant l’insertion du nouveau caractère dans la valeur et ne détecterait pas un collage effectué par un menu. Affecter message.value depuis le code ne déclenche ni input ni change ; appelle aussi directement la fonction de mise à jour.
Recueillir les champs nommés d’un formulaire
form.elements.email.value donne accès à un composant par son nom ou son identifiant. Utilise form.elements["first-name"] pour un nom contenant un trait d’union. La soumission utilise les noms : un identifiant seul n’inclut pas un champ dans les données.
const data = new FormData(form);
const email = data.get("email");
const topics = data.getAll("topics");
FormData recueille les paires nom-valeur actuelles admissibles. Les cases non cochées, les composants désactivés et les champs sans nom sont exclus. get() renvoie la première valeur pour un nom ; getAll() conserve les valeurs répétées, comme plusieurs sujets cochés. Les champs de fichier peuvent fournir des objets fichier ; les champs de texte ordinaires fournissent des chaînes.
Object.fromEntries(data) est pratique pour des noms distincts, mais ne garde que la dernière paire lorsque des noms sont répétés. Choisis getAll() lorsque chaque sélection compte. Comme input remonte par bouillonnement, un seul écouteur sur le formulaire peut lire event.target pour mettre à jour le champ qui a changé.
Points clés
- Convertis la chaîne d’un champ avant un calcul et traite séparément un champ numérique vide.
- Lis l’état d’une case à cocher dans
checked. - Utilise
inputpour les modifications en temps réel etchangepour les choix validés. FormDatainclut les composants nommés admissibles, pas tous les composants.getAll()conserve les valeurs des noms répétés ; la conversion en objet ne le fait pas.- L’affectation d’une valeur par le code n’émet pas d’événement de modification.
4.2 Gère la soumission du formulaire
La soumission appartient au formulaire. Écoute son événement submit pour gérer par une seule voie un clic sur un bouton de soumission, un appui sur Entrée dans un champ sur une seule ligne et un appel de requestSubmit() par script.
Remplacer la navigation par une mise à jour de la page
Normalement, un formulaire envoie des données à l’URL de son action et charge la réponse. Sans action, la destination est la page actuelle. La méthode GET par défaut place les données dans l’URL. Pour mettre à jour la page actuelle avec JavaScript, annule cette action par défaut :
const form = document.querySelector("#new-todo");
form.addEventListener("submit", (event) => {
event.preventDefault();
const data = new FormData(form);
const title = data.get("title").trim();
if (title === "") return;
addTodo(title);
form.reset();
});
Ce formulaire possède un champ de texte activé nommé title. L’écouteur supprime les espaces au début et à la fin, ignore un résultat vide, ajoute un élément et rétablit les valeurs initiales des champs. reset() ne signifie pas toujours vider : un composant ayant une valeur initiale retrouve cette valeur.
Si l’élément apparaît brièvement puis disparaît lorsque la page se recharge, vérifie si preventDefault() a été oublié. Un écouteur de clic sur le bouton seul n’est pas le bon endroit pour gérer le formulaire, surtout lorsqu’une autre voie permet de le soumettre.
Comprendre ce qui déclenche la soumission
La soumission implicite par Entrée peut cliquer sur le bouton de soumission par défaut s’il est activé. Dans une zone de texte, Entrée insère une nouvelle ligne. Un bouton dans un formulaire est par défaut un bouton de soumission lorsque son type est omis : un bouton « Afficher le mot de passe » doit donc utiliser explicitement type="button".
Lorsqu’il y a plusieurs boutons de soumission, event.submitter indique celui qui a été utilisé. Il peut valoir null pour les voies sans bouton précis : le code doit donc le vérifier avant de le lire :
const button = event.submitter;
const intent = button ? button.value : "save";
const data = button ? new FormData(form, button) :
new FormData(form);
Un bouton de soumission nommé, comme name="intent" value="publish", ajoute cette paire lorsqu’il est passé à FormData. Un appel à FormData(form) seul n’inclut pas la paire nom-valeur d’un bouton de soumission.
Préserver le parcours de validation
| Voie de soumission | Validation automatique | Écouteur submit |
|---|---|---|
Activation d’un bouton de soumission ou requestSubmit() | Exécutée sauf si des attributs de validation la désactivent | Exécuté si la validation le permet |
form.submit() | Ignorée | Ignoré |
La validation intégrée s’exécute avant l’événement de soumission. Si un champ obligatoire vide ne passe pas la validation, le navigateur signale le problème et ne déclenche pas submit. Une vérification personnalisée placée uniquement dans cet écouteur ne s’exécutera pas lors de cette tentative échouée. novalidate sur le formulaire désactive l’étape de validation automatique.
Utilise requestSubmit() lorsque le code a besoin du parcours normal de validation et de l’événement de soumission. Cette méthode demande la soumission sans déclencher de clic sur un bouton. Passe un bouton de soumission précis à requestSubmit(button) lorsque les paramètres de soumission de ce bouton doivent s’appliquer.
Points clés
- Gère
submitsur le formulaire pour couvrir les soumissions par l’utilisateur et par script. - Annule la soumission par défaut lorsque JavaScript remplace la navigation.
- Donne
type="button"aux boutons de formulaire qui ne servent pas à la soumission. - Utilise
submitterpour distinguer les boutons de soumission et inclure ses données si nécessaire. - La validation précède
submit;requestSubmit()préserve ce parcours. submit()contourne la validation et l’événement de soumission.reset()rétablit les valeurs initiales.
4.3 Laisse HTML décrire les règles de validation
HTML peut décrire de nombreuses règles de saisie sans test JavaScript personnalisé. Le navigateur vérifie ces règles lors de la soumission et expose les résultats à ton code. Commence par les contraintes qui correspondent aux données dont tu as besoin.
Choisir une contrainte
| Attribut | Règle |
|---|---|
required | Une valeur ou une sélection obligatoire doit être fournie. |
type="email" ou "url" | La valeur doit avoir la syntaxe attendue. |
min, max, step | Les valeurs numériques ou les dates doivent respecter les bornes et les pas. |
minlength, maxlength | Le texte saisi par l’utilisateur doit respecter une règle de longueur. |
pattern | Une valeur textuelle non vide doit correspondre à une expression portant sur toute la valeur. |
Pour pattern="[0-9]{5}", « 12345 » est accepté ; « 1234 », « 123456 » et « 12345a » sont refusés. Le motif couvre toute la valeur, pas une simple partie correspondante. Une entrée vide ignore la vérification du motif : ajoute donc required lorsque l’omission n’est pas autorisée.
La validation d’une adresse e-mail vérifie sa syntaxe, pas l’existence d’une boîte de réception. « ann@example.com » et « ann@example » respectent toutes deux la règle du navigateur, contrairement à « ann.example.com ». Un motif supplémentaire peut imposer un format plus précis si l’application l’exige.
Lire la raison de l’échec
L’objet validity d’un champ contient des indicateurs booléens. valueMissing, typeMismatch, patternMismatch, tooShort et tooLong décrivent du texte manquant ou mal formé. rangeUnderflow, rangeOverflow et stepMismatch décrivent des contraintes numériques. badInput couvre une saisie que le navigateur ne peut pas convertir en valeur exploitable, et customError indique la présence d’un message de validation personnalisé. valid est vrai lorsqu’aucune contrainte n’échoue.
Pour un champ numérique avec min="0" max="10" step="2", 12 dépasse le maximum, 7 ne respecte pas le pas autorisé et 6 est accepté. Plusieurs indicateurs peuvent être vrais ; ne suppose pas que chaque champ invalide présente exactement un problème.
Vérifier silencieusement ou signaler visiblement
checkValidity() renvoie un booléen et déclenche invalid sur les composants invalides sans afficher le message du navigateur. reportValidity() vérifie et signale aussi le problème à l’utilisateur. Appelle l’une ou l’autre méthode sur un champ ou un formulaire. validationMessage fournit le message dans la langue du navigateur. L’événement invalid ne remonte pas par bouillonnement.
Les contraintes de longueur s’appliquent au texte saisi par l’utilisateur. Affecter input.value = "ab" dans le code ne rend pas tooShort vrai simplement parce que minlength vaut 3. maxlength empêche normalement aussi l’utilisateur de saisir davantage de caractères au-delà de sa limite.
Afficher les erreurs au bon moment
:invalid s’applique immédiatement : un champ obligatoire encore intact correspond donc déjà au sélecteur. :user-invalid attend une interaction de l’utilisateur ou une tentative de soumission et peut éviter qu’un champ ne devienne rouge trop tôt. Utilise aussi du texte pour expliquer l’erreur, en plus d’un style visuel.
novalidate ignore la validation automatique du formulaire à la soumission ; formnovalidate l’ignore pour un bouton de soumission. Ces attributs ne suppriment pas les contraintes et ne désactivent pas checkValidity(). Les vérifications du navigateur aident les utilisateurs à corriger leurs erreurs ; le serveur doit valider à nouveau les données reçues, car une requête peut contourner la page.
Points clés
- Utilise les contraintes HTML pour les valeurs obligatoires, la syntaxe, les bornes, les pas, la longueur et les motifs.
- Un motif correspond à la valeur non vide entière ; utilise
requiredpour refuser une entrée vide. - Lis les indicateurs de
validitypour identifier pourquoi un champ est invalide. checkValidity()vérifie ;reportValidity()affiche aussi un message.- Les attributs qui ignorent la validation laissent l’API de validation utilisable.
- Valide aussi les données reçues sur le serveur.
4.4 Règles personnalisées et messages d’erreur utiles
Une règle qui concerne deux champs nécessite du code. Par exemple, une confirmation doit correspondre à un mot de passe ou une date de fin doit être postérieure à une date de début. Sépare la règle de la manière et du moment où son erreur est affichée.
Définir et effacer une erreur personnalisée
Une chaîne non vide passée à setCustomValidity() marque le champ comme invalide et définit customError. Passer "" efface cette erreur personnalisée ; les contraintes required, pattern ou d’autres contraintes peuvent toujours ne pas être respectées.
function checkMatch() {
const matches = confirm.value === password.value;
confirm.setCustomValidity(matches ? "" :
"The passwords do not match.");
}
password.addEventListener("input", checkMatch);
confirm.addEventListener("input", checkMatch);
Vérifie à nouveau les deux champs dont dépend la règle. Modifier le premier mot de passe peut rendre incorrecte une confirmation auparavant correcte. Un message qui n’est jamais effacé garde le champ invalide après la correction de la différence. Exécute aussi la vérification initiale lorsque les champs peuvent contenir des valeurs dès le départ.
Les champs de date fournissent des chaînes ISO comme "2026-03-10", quel que soit le format de date local affiché. Les valeurs non vides de ces composants peuvent être comparées comme du texte. Si la règle impose que la fin soit postérieure au début, refuse end.value <= start.value, y compris l’égalité. Gère les dates manquantes avec required ou une vérification distincte des valeurs vides.
Expliquer la prochaine action utile
Un message doit indiquer le problème et sa correction. Pour une adresse e-mail manquante, indique « Saisis ton adresse e-mail. » Pour un texte d’adresse e-mail mal formé, indique « Saisis une adresse e-mail sous la forme name@example.com. » Conserve la valeur saisie pour que la personne puisse la modifier.
Un champ de nom obligatoire accepte les espaces, car ils forment une chaîne non vide. Vérifie name.value.trim() === "" lorsque les espaces en début et en fin de chaîne ne doivent pas compter. Efface cette erreur personnalisée dès qu’un texte qui a un sens apparaît.
Associer les messages aux composants
<label for="email">Email</label>
<input id="email" name="email" type="email"
required aria-describedby="email-error">
<p id="email-error"></p>
Place l’erreur dans ce paragraphe et définis aria-invalid="true" tant que le champ présente une erreur. Efface le texte et supprime aria-invalid ou définis-le à "false" après correction. aria-describedby associe l’explication au champ pour la technologie d’assistance. Utilise du texte ; une bordure rouge seule ne permet pas à tout le monde de savoir ce qui a échoué.
Choisir le déroulement de la validation
Pour des messages entièrement personnalisés, ajoute novalidate et utilise un écouteur submit sur le formulaire. Mets à jour les règles personnalisées, examine la validité des champs, écris leurs messages et empêche la soumission si l’un d’eux est invalide. Déplace le focus vers le premier champ invalide ou vers un récapitulatif des erreurs contenant des liens. Si JavaScript gère aussi localement la soumission réussie, annule également cette soumission par défaut.
Évite de signaler un texte d’adresse e-mail incomplet dès les premières frappes. Une séquence utile consiste à afficher les erreurs après la perte de focus ou la soumission, puis à vérifier de nouveau sur input une erreur déjà signalée.
Points clés
- Les messages personnalisés non vides rendent un champ invalide ;
""n’efface que cette erreur personnalisée. - Vérifie à nouveau chaque champ dont dépend une règle portant sur plusieurs champs.
- Pour un ordre strict des dates, refuse l’égalité ainsi qu’une date de fin antérieure.
- Explique la correction par du texte et associe ce texte au champ.
- Efface les erreurs visibles et l’état d’erreur ARIA après correction.
- Les messages personnalisés à la soumission nécessitent une gestion explicite de la validité et du focus.
5Crée des composants personnalisés utilisables par tous
Choisir un élément natif fournit une grande partie du comportement d’un composant avant même l’écriture d’un écouteur. Les composants personnalisés demandent le même soin : un nom clair, un accès au clavier, un focus visible et un état qui correspond à ce qu’indique la technologie d’assistance. Les groupes nécessitent un déplacement prévisible entre les éléments. Lorsqu’un contenu s’ouvre, se ferme ou disparaît, une destination de focus choisie volontairement permet à l’utilisateur de poursuivre son interaction sans devoir chercher à nouveau dans la page.
5.1 Commence par un composant natif
Un composant a besoin de plus que d’une réponse au clic. Les personnes doivent pouvoir le trouver, l’atteindre, comprendre son rôle, l’utiliser et voir où se trouve le focus. Le HTML natif fournit déjà une grande partie de ce comportement.
Choisir l’élément adapté
Utilise un <button> pour une action, un <a href> pour la navigation et un composant de formulaire avec un libellé pour la saisie. <details> avec <summary> fournit un composant de divulgation. Mets ces éléments en forme avec CSS pour les adapter à la page. Un bouton qui a le focus s’active avec Entrée ou Espace sans écouteur de touche supplémentaire.
Un div avec un écouteur de clic ne possède ni la sémantique intégrée du bouton ni son comportement au clavier. Lui donner role="button" change ce qu’annonce la technologie d’assistance, mais ne lui permet pas de recevoir le focus et ne transforme pas les appuis sur les touches en clics.
| Besoin | Bouton natif | Div personnalisé servant de bouton |
|---|---|---|
| Rôle | Intégré | Ajouter role="button". |
| Focus au clavier | Intégré | Ajouter tabindex="0". |
| Entrée et Espace | Intégrés | Ajouter la gestion du clavier. |
| Nom accessible | Généralement son texte | Fournir un texte qui a un sens ou un nom ARIA. |
| Comportement désactivé | disabled | Vérifier aria-disabled dans le code. |
Garder un ordre de focus prévisible
tabindex="0" ajoute un élément à la séquence normale de tabulation selon l’ordre du document. tabindex="-1" permet de donner le focus par le code sans ajouter d’arrêt de tabulation. Les valeurs positives placent les éléments avant la séquence habituelle et sont difficiles à maintenir ; évite-les.
Aucun de ces réglages n’ajoute de comportement d’activation. Un bouton personnalisé pouvant recevoir le focus a toujours besoin d’un écouteur pour fonctionner au clavier. Un rôle, un arrêt de tabulation et une fonction de rappel résolvent des parties différentes de l’interaction.
Donner un nom à chaque composant
Un lecteur d’écran utilise un nom accessible pour distinguer les composants. Un bouton textuel peut utiliser son texte visible. Un champ de texte ou une liste déroulante a besoin d’un libellé associé, comme <label for="email">Email</label> associé à id="email". aria-labelledby peut faire référence à un texte visible ailleurs ; aria-label peut fournir un nom lorsqu’il n’existe pas de texte visible adapté.
Un bouton de fermeture composé uniquement d’une icône peut être <button type="button" aria-label="Close">×</button>. Le nom décrit l’action au lieu de laisser l’utilisateur deviner le sens du symbole.
Afficher et faire respecter l’état
Garde un indicateur de focus visible. Si tu remplaces le contour par défaut, fournis un remplacement clair avec :focus-visible, par exemple outline: 3px solid #1a73e8. Le supprimer sans remplacement cache la position de l’utilisateur du clavier.
Un bouton natif désactivé quitte la séquence de tabulation et ne peut pas être activé normalement. aria-disabled="true" ne fait que communiquer son indisponibilité. Les actions au clic et au clavier d’un composant personnalisé doivent vérifier cet état et quitter la fonction sans agir. Centraliser cette vérification dans la fonction d’activation maintient la cohérence des deux modes d’entrée.
Points clés
- Utilise un élément natif adapté à l’action ou à la saisie.
- Un rôle ARIA fournit une sémantique, pas un comportement.
- Utilise
tabindex="0"pour l’accès normal par Tabulation et-1pour un focus donné uniquement par le code. - Fournis un nom accessible et un indicateur de focus visible.
- Fais respecter
aria-disableddans le code d’activation.
5.2 Associe le comportement au clavier et l’état
Un composant personnalisé doit donner le même résultat quelle que soit sa méthode d’activation. Garde l’action dans une seule fonction, dirige vers elle les utilisations au clavier et au pointeur, et mets à jour l’état lu à la fois par les styles et par la technologie d’assistance.
Permettre l’activation au clavier d’un bouton personnalisé
fakeButton.addEventListener("click", activate);
fakeButton.addEventListener("keydown", (event) => {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
activate();
}
});
Ce code concerne un bouton personnalisé pouvant recevoir le focus. Annuler l’action d’Espace empêche le défilement de la page pendant son exécution. Un bouton natif produit déjà des clics lors de son activation au clavier : lui ajouter une seconde voie au clavier peut donc exécuter l’action deux fois.
Choisir l’état adapté au composant
| Composant | État |
|---|---|
| Bouton à bascule avec un libellé stable | aria-pressed="true" ou "false" |
| Bouton ouvrant un composant de divulgation | aria-expanded="true" ou "false" |
| Case à cocher ou interrupteur personnalisé | aria-checked="true" ou "false" |
Un bouton à bascule « Couper le son » garde ce libellé et modifie aria-pressed. Si le libellé de l’action devient « Activer le son », omets aria-pressed. Une case à cocher utilise role="checkbox" et Espace pour changer d’état ; un interrupteur utilise role="switch" pour les états activé et désactivé.
Les attributs contiennent des chaînes. Compare getAttribute("aria-expanded") avec "true", et non avec le booléen true :
detailsButton.addEventListener("click", () => {
const open = detailsButton.getAttribute(
"aria-expanded") === "true";
detailsButton.setAttribute("aria-expanded", String(!open));
panel.hidden = open;
});
Lorsque open était vrai, le nouvel état est faux et le panneau devient masqué. aria-controls peut identifier le panneau par son identifiant. Les éléments natifs <details> et <summary> fournissent le comportement de divulgation sans ce script.
Utilise l’attribut d’état comme source pour les styles, par exemple [aria-pressed="true"], afin que les états visible et annoncé changent ensemble. Ferme les éléments contextuels avec Échap et rends le focus à leur élément déclencheur.
Donner un seul arrêt de tabulation à un groupe
Les onglets, les barres d’outils et les groupes de boutons radio utilisent Tabulation pour entrer dans le groupe ou en sortir et les touches fléchées pour s’y déplacer. Le tabindex itinérant maintient l’élément courant à 0 et les autres à -1. Lors d’un déplacement, définis l’ancien élément à -1, le nouveau à 0 et donne le focus au nouvel élément.
Pour trois éléments, un déplacement vers la droite depuis l’indice 2 revient à 0 avec (2 + 1) % 3. Vers la gauche depuis 0, (0 - 1 + 3) % 3 permet d’atteindre 2. Ajoute la longueur avant l’opération de reste, car en JavaScript -1 % 3 vaut −1.
Vérifie au clavier : atteins le composant, vois le focus, active-le avec les touches appropriées, déplace-toi dans un groupe et ferme un élément contextuel avec Échap. Vérifie l’état visible et l’état ARIA à chaque changement.
Points clés
- Dirige le clic, Entrée et Espace d’un bouton personnalisé vers une seule action.
- Les boutons natifs fournissent déjà l’activation par clic au clavier.
- Choisis
aria-pressed,aria-expandedouaria-checkedselon l’état à représenter. - Compare les valeurs ARIA comme des chaînes et mets à jour les styles à partir du même état.
- Le tabindex itinérant donne à un groupe un seul arrêt de tabulation et permet les déplacements avec les touches fléchées.
- Échap ferme un élément contextuel et rend le focus à son élément déclencheur.
5.3 Déplace le focus lorsque la page change
Le focus détermine où va la prochaine action au clavier. Si le composant qui a le focus disparaît, l’utilisateur peut perdre sa place. Traite le focus comme une partie de la mise à jour de la page, en particulier lors de l’ouverture d’une boîte de dialogue, de la suppression d’un élément ou du signalement d’une erreur.
Ouvrir une boîte de dialogue et revenir à son élément déclencheur
Mémorise l’élément qui a le focus avant l’ouverture. Déplace le focus dans la nouvelle interaction, puis rétablis-le à la fermeture :
let opener;
openButton.addEventListener("click", () => {
opener = document.activeElement;
dialog.showModal();
});
dialog.addEventListener("close", () => {
if (opener && opener.isConnected) opener.focus();
});
showModal() sur une boîte de dialogue native déplace le focus à l’intérieur et rend le reste de la page inerte : il est donc impossible de cliquer dessus ou de lui donner le focus tant que la boîte modale est ouverte. Échap provoque normalement un événement cancel, suivi de la fermeture et d’un événement close. Un écouteur cancel peut empêcher la fermeture si l’application nécessite ce comportement.
Choisis une destination initiale utile pour le focus dans la boîte de dialogue, comme son premier composant pertinent. Pour un élément contextuel personnalisé, le code doit déplacer volontairement le focus. Lorsque l’élément déclencheur d’origine n’existe plus, choisis plutôt un composant utile à proximité au lieu d’essayer de donner le focus à un élément détaché.
Rendre une destination utile accessible au focus
Un titre ou un récapitulatif des erreurs ne peut normalement pas recevoir le focus. Donne-lui tabindex="-1" avant d’appeler .focus(). Il peut alors recevoir le focus volontairement sans devenir un arrêt supplémentaire pendant la navigation normale par Tabulation. N’utilise 0 que s’il appartient à cette séquence normale.
Préserver la position après une suppression
Avant de supprimer un élément de liste dont le bouton de suppression a le focus, trouve la prochaine destination utile. Donne le focus au bouton de l’élément suivant ; s’il n’y a pas d’élément suivant, utilise le bouton de l’élément précédent. Si la liste devient vide, donne le focus à son titre avec tabindex="-1".
Trouver la destination avant la suppression évite de perdre le lien avec les éléments voisins. N’envoie pas le focus en haut du document après chaque suppression ; la personne doit pouvoir continuer à travailler près de l’endroit modifié.
Garder le focus dans une interaction en cours
Un élément contextuel peut se fermer lorsque le focus quitte toute sa zone. L’événement focusout, qui remonte par bouillonnement, fournit la destination :
menu.addEventListener("focusout", (event) => {
if (!menu.contains(event.relatedTarget)) {
menu.hidden = true;
}
});
Passer d’un composant du menu à un autre ne le ferme pas, car la destination reste à l’intérieur. Une destination null est aussi à l’extérieur ; contains(null) est faux. Ne rends pas automatiquement le focus à l’élément déclencheur lorsque l’utilisateur l’a volontairement déplacé vers un autre composant de la page.
Rendre les changements prévisibles
Après l’échec d’une validation personnalisée de formulaire, donne le focus au premier champ invalide ou à un récapitulatif des erreurs contenant des liens vers celles-ci. La validation intégrée donne déjà le focus à un champ invalide. Garde le texte d’erreur disponible pour que la personne sache quoi corriger.
Ne passe pas à un nouveau champ pendant que l’utilisateur saisit du texte et ne lance pas une navigation dès qu’une liste déroulante change. Laisse une action claire confirmer le changement. Le déplacement du focus doit accompagner une action volontaire ou une correction, sans interrompre la saisie ordinaire.
Points clés
- Mémorise l’élément déclencheur et rétablis le focus sur une destination disponible à la fermeture d’une boîte de dialogue.
- Utilise
tabindex="-1"pour un titre ou un récapitulatif auquel le code donne le focus. - Après une suppression, donne le focus à un élément voisin ou au titre de la liste vide.
- Utilise
relatedTargetpour distinguer un déplacement interne du focus d’une sortie de l’élément contextuel. - Après une validation échouée, donne le focus à une destination liée aux erreurs ; évite les déplacements inattendus du focus.
Événements JavaScript : exemples
1Crée et examine des écouteurs d’événements
13 étapes
- 1IntroductionFais réagir un bouton
Un écouteur relie un événement à une fonction. Construis un petit compteur en choisissant le bouton, en enregistrant son action et en conservant le total entre les appels. Examine ensuite un
clickimbriqué et contrôle la durée de vie de l’écouteur.Observe la différence entre le code de mise en place, qui s’exécute maintenant, et la fonction de rappel, que le navigateur appelle lorsque l’événement choisi se produit.
- 2ExempleStocke le total hors de la fonction de rappel
Sélectionne le bouton existant et stocke son compteur avant l’enregistrement :
const button = document.querySelector("#like"); let likes = 0; button.addEventListener("click", () => { likes = likes + 1; button.textContent = "Likes: " + likes; });Chaque appel augmente le total précédent. Après trois clics, le libellé est « Likes: 3 ». Un compteur déclaré dans la fonction de rappel repartirait de zéro à chaque appel.
- 3ConseilPasse l’action sans l’appeler
addEventListener("click", showMenu)passe une fonction pour une utilisation ultérieure.showMenu()l’appellerait pendant la mise en place. Lorsque des arguments sont nécessaires, utilise() => showMenu("main").Charge le script après la création du bouton, par exemple avec
defer, et respecte l’orthographe exacte de l’événement. Un écouteur de"Click"ne reçoit pas les événements"click"ordinaires. - 4DéfiCorrige un enregistrement
Un bouton doit ouvrir le panneau de conseils à chaque activation. La mise en place utilise actuellement
button.addEventListener("click", openTips()). Que faut-il changer et pourquoi ?---reveal---
Passe
openTipssans parenthèses. Cela fournit la fonction de rappel à exécuter lors d’unclickultérieur. AppeleropenTips()pendant la mise en place ouvre immédiatement le panneau et passe son résultat au lieu de conserver l’action pour l’événement. - 5ExplicationLis les deux propriétés d’élément
Pour un bouton contenant une image, cliquer sur l’image fait d’elle la
target. Dans l’écouteur du bouton,currentTargetest le bouton.La propriété
targetindique où l’événement a commencé ; la cible courante, distincte detarget, indique où cette fonction de rappel a été enregistrée. Cette différence explique pourquoi lire ledatasetd’un bouton depuistargetpeut échouer lorsque leclickatteint son image. - 6ExempleLis les données du bouton qui les possède
Supposons que
buttonpossèdedata-id="7"et contienne une icône :button.addEventListener("click", (event) => { console.log(event.currentTarget.dataset.id); });Le résultat est
"7"aussi bien pour unclicksur l’icône que pour unclicksur l’arrière-plan du bouton. La même expression fonctionne dans un écouteur écrit avec une fonction fléchée ou classique. Lethisd’une fonction fléchée ne désigne pas automatiquement le bouton. - 7DéfiIdentifie l’élément auquel appartient l’écouteur
Une section contient un bouton avec un span. Un écouteur
clickest ajouté uniquement à la section et l’utilisateur clique sur le span. Que désignenttargetetcurrentTargetpendant cette fonction de rappel ?---reveal---
targetdésigne le span où l’événement a commencé.currentTargetdésigne la section à laquelle l’écouteur a été ajouté. L’origine de l’événement n’est pas remplacée par l’ancêtre qui le reçoit. - 8ExplicationGarde la référence pour la suppression
La suppression nécessite le même type d’événement, le même objet fonction de rappel et le même réglage de capture :
const handler = () => closePanel(); button.addEventListener("click", handler); button.removeEventListener("click", handler);Une fonction anonyme peut être supprimée lorsque sa référence est enregistrée ainsi. Écrire un nouveau
() => closePanel()dans l’appel de suppression crée un autre objet qui ne correspond pas à l’enregistrement précédent. - 9LienMets fin à plusieurs enregistrements ensemble
Une fonctionnalité temporaire peut passer un seul signal
AbortControllerà plusieurs enregistrements. Appelercontroller.abort()supprime ces écouteurs, y compris les fonctions de rappel enregistrées ou anonymes.Utilise un nouveau contrôleur pour une autre période d’utilisation. Pour une réponse unique,
{ once: true }supprime cet enregistrement après son exécution. Aucune des deux options n’empêche des fonctions de rappel distinctes de s’accumuler avant la fin de leur durée de vie. - 10DéfiDiagnostique une mise en place répétée
L’ouverture d’un panneau enregistre à chaque fois un nouvel écouteur de touches anonyme sur le document. La fermeture masque le panneau mais laisse l’écouteur en place. Après trois ouvertures, une touche déclenche trois actions. Comment corriger ce cycle de vie ?
---reveal---
Supprime les enregistrements lorsque le panneau se ferme, par exemple en annulant leur signal partagé, et crée un nouveau contrôleur à la réouverture. Tu peux aussi enregistrer une fonction de rappel et supprimer cette même référence. Masquer le panneau ne supprime pas un écouteur sur le document.
- 11Point cléDéclenche immédiatement une notification
Pour informer un autre code, crée un
CustomEventavec ses données dansdetail. Définisbubbles: truesi les ancêtres doivent le recevoir :item.dispatchEvent(new CustomEvent("cart:add", { detail: { id: 42 }, bubbles: true }));Les écouteurs s’exécutent avant le retour de l’appel. L’événement déclenché a
isTrustedà faux. C’est une notification envoyée par ton code, pas une demande au navigateur d’attendre une action de l’utilisateur. - 12DéfiCombine origine et durée de vie
Le gestionnaire
clickd’un bouton utilise son propredata-keyet ne doit agir qu’à la première activation. Il contient une icône SVG. Quels propriété et option permettent de satisfaire les deux exigences ?---reveal---
Lis
event.currentTarget.dataset.keydans l’écouteur ajouté directement au bouton et enregistre-le avec{ once: true }. La propriété désigne le bouton concerné même lors d’unclicksur l’icône. L’option supprime cet enregistrement après son premier appel. - 13RécapitulatifVérifie un écouteur à trois endroits
Lorsqu’une interaction échoue, examine la mise en place, les données de la fonction de rappel et sa durée de vie. Vérifie que l’élément existe et que le nom de l’événement est exact ; examine
targetetcurrentTargetpendant l’appel ; puis cherche une suppression manquante ou un enregistrement répété. Ces vérifications permettent de distinguer un écouteur qui ne reçoit jamais d’événement d’un écouteur qui le reçoit correctement mais agit sur le mauvais élément.
2Suis les événements et délègue les actions
13 étapes
Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.
- 1IntroductionSuis un clic dans une fiche
- 2ExempleLis le trajet de remontée
- 3ExplicationAjoute le trajet de descente
- 4DéfiSuis un arbre plus petit
- 5ExplicationRemplace la navigation
- 6Point cléArrêter la propagation est un choix distinct
- 7DéfiGarde un observateur parent actif
- 8ExplicationDéplace l’écouteur sur la liste
- 9ExempleTrouve et vérifie le bouton de suppression
- 10DéfiGère une icône imbriquée
- 11ConseilUtilise un événement qui atteint le conteneur
- 12DéfiSépare l’ouverture et la fermeture
- 13RécapitulatifChoisis où gérer chaque action
3Gère les touches et crée un glissement au pointeur
16 étapes
Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.
- 1IntroductionChoisis le bon niveau d’entrée
- 2ExplicationDistingue le sens de la position
- 3ConseilProtège la saisie et gère les répétitions
- 4DéfiChoisis un événement pour un aperçu
- 5LienRends l’activation accessible au clavier
- 6ExempleChange de repère de coordonnées
- 7DéfiExamine un clic après défilement
- 8Point cléÉvite de faire du survol le seul accès
- 9ExempleCalcule un mouvement de glissement
- 10ExplicationStocke le départ et capture le pointeur
- 11ExempleApplique le déplacement à chaque mouvement
- 12ConseilTermine le glissement même si le navigateur reprend la main
- 13DéfiPrévois la suite d’un glissement
- 14LienPropose un déplacement sans glissement
- 15DéfiDiagnostique deux échecs de glissement
- 16RécapitulatifAssocie l’événement à la tâche
4Crée une interaction complète avec un formulaire
16 étapes
Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.
- 1IntroductionSuis un formulaire de la modification à la soumission
- 2ExempleLis un nombre sans concaténation
- 3ExplicationLis les choix et les noms répétés
- 4DéfiConserve chaque sujet sélectionné
- 5ExplicationGère la soumission sur le formulaire
- 6ExempleLis, ajoute et réinitialise
- 7DéfiConserve le parcours normal de soumission
- 8ExempleLis les échecs de contraintes indépendantes
- 9Point cléUn motif n’exige pas de valeur
- 10DéfiVérifie un intervalle avec un pas
- 11ExplicationAjoute une règle reliant deux champs
- 12ConseilDistingue la validité du moment d’affichage des erreurs
- 13DéfiCorrige une règle de dates non actualisée
- 14LienPrends en charge les messages lorsque ceux du navigateur sont désactivés
- 15DéfiComplète le parcours de correction
- 16RécapitulatifVérifie les parcours valides et invalides
5Crée des composants et préserve la position au clavier
14 étapes
Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.
- 1IntroductionRends une interaction utilisable au clavier
- 2ExplicationUtilise le comportement déjà fourni par HTML
- 3ConseilDéfinis l’accès au focus selon le besoin
- 4DéfiCorrige une action inaccessible
- 5ExempleGarde une seule fonction d’activation
- 6ExplicationExprime le bon type d’état
- 7DéfiInverse correctement un composant de divulgation
- 8ExempleDéplace un arrêt de tabulation dans un groupe
- 9LienMémorise l’origine d’une boîte de dialogue
- 10ExempleMaintiens ouvert l’élément lors d’un déplacement interne du focus
- 11DéfiChoisis le focus après une suppression
- 12DéfiSuis la mise à jour d’un groupe
- 13DéfiRends un élément contextuel prévisible
- 14RécapitulatifTeste la séquence complète du composant
Événements JavaScript : QCM
Série 1 : Suis les actions imbriquées et la délégation10 Questions Pratiques
Question 1 sur 10
Afficher la réponseMasquer la réponse
Question 2 sur 10
Afficher la réponseMasquer la réponse
Question 3 sur 10
focus ordinaire, mais donner le focus à son champ enfant ne l’appelle pas. Comment le formulaire peut-il observer le focus de ses descendants sans utiliser la capture ?Afficher la réponseMasquer la réponse
focusin remonte par bouillonnement depuis le champ jusqu’à son formulaire : un écouteur ordinaire sur le formulaire peut donc l’observer. focus et blur ne remontent pas. Une option d’écouteur ne peut pas changer le comportement de bouillonnement de l’événement du navigateur ; lire une propriété dans une fonction de rappel qui ne s’exécute jamais ne peut pas résoudre l’absence de l’événement.Question 4 sur 10
event.stopPropagation(). Qu’arrive-t-il à sa navigation normale ?Afficher la réponseMasquer la réponse
preventDefault() dans un écouteur qui peut annuler l’événement lorsque le code remplace la navigation par une action dans la page.Question 5 sur 10
preventDefault(). Un écouteur de soumission ordinaire existe aussi sur une section qui l’entoure. Que peut observer l’écouteur de la section ?Afficher la réponseMasquer la réponse
Question 6 sur 10
Afficher la réponseMasquer la réponse
Question 7 sur 10
Afficher la réponseMasquer la réponse
closest() part du SVG cliqué et remonte jusqu’au bouton. matches() ne teste que le SVG et ne peut donc pas identifier le composant qui l’entoure. Chercher vers le bas avec querySelector() suit aussi la mauvaise direction pour un bouton qui contient la cible de l’événement.Question 8 sur 10
Afficher la réponseMasquer la réponse
Question 9 sur 10
closest(".action") dans un conteneur imbriqué dans un élément extérieur .action. Un clic dans un espace vide trouve cet élément extérieur. Quelle vérification limite le traitement au conteneur ?Afficher la réponseMasquer la réponse
closest() peut remonter au-delà du conteneur de l’écouteur et renvoyer un ancêtre extérieur. Après avoir vérifié qu’un élément a été trouvé, utilise container.contains(match) pour exclure ce résultat. Tester currentTarget === container exclurait tous les événements dans cet écouteur, y compris les clics valides sur ses propres composants enfants.Question 10 sur 10
closest(".remove") et des vérifications d’appartenance. Les nouveaux boutons fonctionnent, sauf sur une ligne dont l’écouteur de l’icône appelle stopPropagation(). La zone de remplissage du bouton de cette même ligne fonctionne. Pourquoi cette différence ?Afficher la réponseMasquer la réponse
closest() peut gérer une icône comme cible, mais ne peut pas aider une fonction de rappel déléguée qui ne reçoit jamais l’événement.Série 2 : Configure et examine des écouteurs d’événements10 Questions Pratiques
Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.
Question 1 sur 10
showHints uniquement lorsqu’il est activé. Quel enregistrement permet cela ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 2 sur 10
addEventListener. Quelle modification du chargement permet d’attendre que le HTML soit analysé avant la sélection ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 3 sur 10
const items = document.querySelectorAll(".choice"); items.addEventListener("click", choose);. Tous les choix existent déjà. Pourquoi cela échoue-t-il et comment faut-il modifier la mise en place ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 4 sur 10
button.onclick = first; button.onclick = second;. Que se passe-t-il lorsque l’utilisateur clique une fois sur le bouton ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 5 sur 10
target et currentTarget pendant l’exécution de cet écouteur ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 6 sur 10
<button data-code="r8"><span>Run</span></button> lit event.target.dataset.code. Pourquoi cette expression peut-elle renvoyer undefined, et quelle expression permet à l’écouteur direct de lire le code du bouton ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 7 sur 10
currentTarget: null. Comment le développeur peut-il examiner l’élément auquel appartient l’écouteur pendant l’appel ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 8 sur 10
{ capture: true }. Le même type et la même fonction sont passés à removeEventListener, mais aucun troisième argument n’est fourni. Pourquoi la fonction de rappel reste-t-elle enregistrée ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 9 sur 10
board.addEventListener("click", () => mark()). Après deux démarrages, un clic sur le plateau place deux marques. Quel changement de mise en place empêche cette accumulation ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 10 sur 10
Un bouton sans autre écouteur reçoit les enregistrements suivants, puis l’utilisateur clique deux fois dessus. Combien de fois log s’exécute-t-elle au total ?
button.addEventListener("click", log, { once: true });
button.addEventListener("click", log);
button.addEventListener("click", log, true);
button.removeEventListener("click", log);
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Série 3 : Gère les entrées au clavier, au pointeur et par glissement10 Questions Pratiques
Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.
Question 1 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 2 sur 10
keydown. Quel changement corrige les deux symptômes ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 3 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 4 sur 10
pointerdown. Quel événement doit gérer l’action ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 5 sur 10
clientY à 75. Quelle est sa coordonnée verticale par rapport au document ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 6 sur 10
pointerout. Quel événement détecte mieux la sortie de la fiche entière ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 7 sur 10
left: 65px; top: 90px. Son pointeur part de 180, 210 et se déplace jusqu’à 155, 245 en coordonnées client. Quelle position la boîte doit-elle atteindre ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 8 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 9 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 10 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Série 4 : Lis les données de formulaire et diagnostique la validation10 Questions Pratiques
Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.
Question 1 sur 10
"6". Que produit input.value + 2 ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 2 sur 10
topic, avec les valeurs "art" et "code" dans l’ordre du document, un champ topic non coché de valeur "music" et une note nommée désactivée. Que renvoie new FormData(form).getAll("topic") et pourquoi la conversion en objet présente-t-elle un risque ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 3 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 4 sur 10
form.submit(), et l’écouteur du formulaire qui empêche la navigation ne s’exécute jamais. Quel appel rétablit le parcours attendu et que se passe-t-il avant la correction du champ ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 5 sur 10
pattern="[A-Z]{3}". Une valeur vide satisfait-elle cette contrainte de motif ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 6 sur 10
min="2" max="14" step="4". L’utilisateur saisit 12. Quelle contrainte échoue ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 7 sur 10
novalidate et vérifie les champs dans l’ordre du document à la soumission. Son champ de quantité est obligatoire avec min="2" max="14" step="4" ; il contient maintenant 10 et un ancien message personnalisé a été effacé avec setCustomValidity(""). Le champ suivant est une adresse e-mail obligatoire qui est vide. Quel champ doit bloquer cette tentative et recevoir le focus ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 8 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 9 sur 10
end.value < start.value et ne s’exécute que lors des modifications de la fin. Quels deux changements corrigent les défauts restants entre les champs ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 10 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Série 5 : Crée un accès au clavier et préserve le focus10 Questions Pratiques
Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.
Question 1 sur 10
role="button" et un écouteur de clic. Que fournit le rôle lui-même ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 2 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 3 sur 10
activate(). Il possède aria-disabled="true". La fonction commence par if (button.getAttribute("aria-disabled") === true) return;, mais les deux voies continuent à agir. Quelle correction fait respecter l’état désactivé tout en permettant d’agir lorsque l’état est la chaîne « false » ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 4 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 5 sur 10
aria-expanded="true" et un panneau visible. Son gestionnaire de clic lit l’ancien état développé. Quel doit être l’état suivant ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 6 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 7 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 8 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 9 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 10 sur 10
tabindex="-1". Le bouton de suppression du dernier élément, qui a le focus, supprime cet élément ; plus tard, l’élément restant est lui aussi supprimé. Quelle séquence de focus permet de continuer à utiliser le clavier ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Tu bloques sur ton propre exercice ? Aide aux Devoirs
Mots-Clés
A
AbortController
abort() est appelée.Action par défaut
Activation
click pour l’utilisation au pointeur et l’utilisation native au clavier.click, qu’il soit activé avec Espace ou avec une souris.Alternative à pointeur unique
aria-describedby
aria-describedby associe un composant à un texte descriptif en énumérant les identifiants des éléments qui contiennent ce texte.email-error pour que la technologie d’assistance puisse lui associer l’erreur.aria-invalid
aria-invalid indique que la valeur saisie dans un composant comporte une erreur ; le code doit le mettre à jour lorsque l’erreur change.aria-invalid="true" tant que son message de correction est affiché à côté.Arrière-plan inerte
Attribut de données
data- qui stocke des informations de l’application accessibles par le dataset d’un élément.data-action="clear" sous la forme button.dataset.action pour sélectionner une action connue.B
Boîte de dialogue modale
showModal() ouvre la boîte de dialogue native et déplace le focus dans son contenu.Bouillonnement
bubbles est vraie.input d’un champ enfant remonte par bouillonnement jusqu’à un écouteur enregistré sur le formulaire qui le contient.Bouton à bascule
aria-pressed qui indique l’état actuel.aria-pressed passe de vrai à faux et inversement.Bouton de soumission
event.submitter lorsqu’un bouton particulier a lancé cette soumission.C
cancelable
cancelable est un booléen qui indique si un événement permet d’annuler son action par défaut avec preventDefault().input signale une modification déjà effectuée : sa propriété cancelable est donc fausse.Capture du pointeur
checked
checked est l’état booléen qui indique si une case à cocher ou un bouton radio est sélectionné, indépendamment de sa valeur de soumission.checkbox.checked pour décider s’il doit afficher une section facultative.checkValidity
checkValidity() renvoie si les contraintes sont respectées et déclenche des événements invalid en cas d’échec, sans afficher de message du navigateur.closest
closest() vérifie un élément puis ses ancêtres pour trouver le plus proche qui correspond au sélecteur, et renvoie null si aucun ne correspond.closest("button") trouve le bouton d’action qui l’entoure.code
code indique la position physique d’une touche indépendamment du caractère produit par la disposition actuelle du clavier.code lorsque ses commandes de déplacement doivent rester à des positions physiques fixes.Composant de divulgation
aria-expanded.Composant natif
contains
contains() vérifie si un nœud est l’élément lui-même ou l’un de ses descendants et renvoie un résultat booléen.list.contains(button) avant d’autoriser l’action du bouton.Contrainte de validation personnalisée
setCustomValidity(), dont un message non vide marque le composant comme invalide.Coordonnées dans la zone d’affichage
clientX et clientY.Coordonnées dans le document
pageX et pageY, défilement compris.pageY à 400.currentTarget
currentTarget indique l’objet dont l’écouteur s’exécute et est réinitialisée à null après la fin du déclenchement de l’événement.currentTarget permet au code de lire les données de ce bouton.CustomEvent
detail et être configuré pour remonter par bouillonnement jusqu’aux ancêtres."cart:add" avec son identifiant dans detail de l’événement.D
Déclenchement synchrone
dispatchEvent(), avant que cette méthode rende la main au code appelant.dispatchEvent() apparaît après les messages de ses écouteurs.defaultPrevented
defaultPrevented est un booléen qui indique si l’action par défaut d’un événement a été annulée avec succès.defaultPrevented avant de décider comment gérer un clic.Délégation d’événements
É
Écouteur d’événements
Écouteur passif
preventDefault() dans un écouteur tactile passif n’arrête pas le défilement du navigateur.Élément déclencheur
État ARIA
aria-checked de l’interrupteur est mise à jour lorsque son apparence visible passe de l’état activé à l’état désactivé ou inversement.État du glissement
Événement
click permet à la page de réagir lorsqu’une personne active le bouton suivant de la galerie.Événement change
change signale une modification validée par l’utilisateur, comme quitter un champ de texte modifié ou choisir un nouvel état pour une case à cocher ou une liste déroulante.change lorsque l’utilisateur le quitte pour passer au composant suivant.Événement de pointeur
pointermove peut lire le mouvement d’une souris ou d’un contact tactile.Événement input
input signale une modification effectuée par l’utilisateur après le changement de valeur d’un composant, y compris une modification de texte sans appui physique sur une touche.input du champ.Événement submit
submit est un événement de formulaire annulable, déclenché pendant le parcours normal de soumission après que la validation automatique a autorisé l’envoi.submit d’un formulaire gère une soumission valide en ajoutant un élément localement et en annulant la navigation.F
Focus
document.activeElement.search.focus() dirige le prochain caractère saisi vers le champ de recherche.FormData
data.getAll("topics") récupère ensemble toutes celles qui sont sélectionnées.G
Gestion du focus
Groupe de composants composite
I
Identité d’un écouteur
Indicateur de focus
:focus-visible montre quel bouton de la barre d’outils recevra la prochaine action au clavier.Indicateur de touche de modification
ctrlKey ou metaKey avec la lettre S.K
key
key indique la valeur produite par une touche, compte tenu de la disposition du clavier et des touches de modification comme Maj.key d’une lettre de "a" à "A" tandis que sa position reste identique.keydown
keydown signale l’appui sur une touche avant son effet normal de modification et peut se répéter tant que la touche physique reste enfoncée.keydown avant de fermer le panneau ouvert.M
Masque de bits des boutons
buttons de l’événement.buttons à 3, en combinant les indicateurs 1 et 2.N
Nom accessible
aria-label="Close" pour indiquer l’action de son symbole.novalidate
novalidate ignore la validation automatique des contraintes à la soumission tout en laissant disponibles les contraintes et les méthodes de validation.novalidate pour que son écouteur de soumission puisse examiner lui-même chaque champ.O
Objet événement
key de l’événement reçu pour décider s’il doit fermer un panneau.once
once demande la suppression automatique de cet enregistrement après son premier appel pour le type d’événement choisi.once: true pour le clic qui la ferme pendant cette période d’utilisation.P
pattern
pattern définit une contrainte par expression régulière portant sur la valeur entière des champs de texte compatibles, appliquée uniquement lorsque leur valeur n’est pas vide.required pour refuser un champ vide.Phase cible
eventPhase à 2 pendant leur appel.Phase de capture
pointercancel
pointercancel indique que le navigateur a annulé l’interaction du pointeur, ce qui oblige à effacer l’état actif d’un glissement.pointercancel.pointerId
pointerId identifie un pointeur individuel pendant une interaction afin que les contacts simultanés puissent être gérés séparément.preventDefault
preventDefault() annule l’action par défaut d’un événement qui peut l’être dans un écouteur non passif, sans arrêter sa propagation.preventDefault() avant d’ajouter un élément local sans navigation.Propagation
Propriété de gestionnaire d’événements
onclick, qui contient une seule fonction de rappel d’événement et la remplace lors d’une nouvelle affectation.button.onclick remplace le gestionnaire précédent de cette propriété.R
Récapitulatif des erreurs
Référence de fonction
openPanel enregistre la fonction ; passer openPanel() l’appelle pendant la mise en place.Réinitialisation de formulaire
form.reset() rétablit les valeurs initiales de ses champs.relatedTarget
relatedTarget indique l’autre élément concerné par un changement de focus, ou vaut null lorsqu’aucun élément de ce type n’est disponible.focusout d’un menu vérifie si la destination reste dans le menu.reportValidity
reportValidity() vérifie les contraintes et demande aussi au navigateur d’afficher un message de validation pour les échecs non gérés.reportValidity() pour aider l’utilisateur à trouver un champ invalide.requestSubmit
requestSubmit() demande la soumission d’un formulaire selon le parcours normal de validation et de l’événement submit, sans déclencher de clic sur un bouton.form.requestSubmit() pour que la validation et l’écouteur de soumission du formulaire s’exécutent.Rôle ARIA
role="button" a toujours besoin de code pour l’activation et d’un arrêt de tabulation adapté.S
stopImmediatePropagation
stopImmediatePropagation() arrête la propagation de l’événement et ignore aussi les écouteurs restants enregistrés sur la cible courante de l’événement.stopPropagation
stopPropagation() empêche un événement de se propager vers d’autres éléments tout en laissant actifs les autres écouteurs sur son élément courant.Suppression des espaces en début et en fin de chaîne
name.value.trim() === "" détecte un nom composé uniquement d’espaces.T
tabindex
tabindex contrôle la participation à la tabulation ordinaire et la capacité à recevoir le focus depuis le code : 0 place l’élément dans l’ordre normal et −1 hors de cette séquence.tabindex="-1" pour que le code puisse lui donner le focus sans ajouter d’arrêt normal de tabulation.Tabindex itinérant
target
target indique l’origine de l’événement, qui peut être un élément imbriqué dans le composant dont l’action est gérée.target du clic.Test de clic à l’extérieur
touch-action
touch-action déclare quels gestes tactiles du navigateur sont autorisés lorsqu’un geste commence sur un élément.touch-action: none sur la surface de glissement réserve le mouvement dans cette zone au glissement.V
Validation des contraintes
ValidityState
validity d’un composant, avec des indicateurs booléens qui identifient les contraintes non respectées.stepMismatch même si elle se trouve entre son minimum et son maximum.value
value expose la valeur actuelle d’un composant de formulaire sous forme de texte, y compris celle des champs numériques dont le contenu doit encore être converti."8" nécessite une conversion avant que le code puisse lui ajouter une valeur numérique.valueAsNumber
valueAsNumber lit directement la valeur numérique d’un champ compatible et renvoie NaN lorsqu’aucune valeur numérique exploitable n’est présente.NaN, que le code détecte avec Number.isNaN().À propos de cette unité
Crée ton propre Matériel d'Étude
Transforme tes notes, diapos et documents en Guides d'Étude, Questions Pratiques, Flashcards et 6 autres outils.