
Événements clavier JavaScript : key, code, keyCode et comment les déboguer
📷 Life Of Pix / PexelsÉvénements clavier JavaScript : key, code, keyCode et comment les déboguer
Un guide pratique sur les événements clavier JavaScript — pourquoi keyCode est obsolète, comment key et code diffèrent, et comment créer des raccourcis fiables qui fonctionnent sur tous les navigateurs et dispositions de clavier.
Ce bug, je l'ai rencontré plus d'une fois : j'écris un gestionnaire de raccourci clavier dans Chrome, tout fonctionne parfaitement, je déploie, et puis je reçois un rapport de bug de quelqu'un sur Firefox. Même code, comportement différent. Après une heure de fouille, je trouve le coupable — j'utilisais e.keyCode pour détecter la touche, et il retournait des valeurs différentes selon le navigateur et la disposition du clavier.
Ce bug est entièrement évitable. C'est pourquoi il vaut la peine de comprendre correctement les événements clavier JavaScript. Cet article parcourt le modèle complet des événements clavier — quels événements se déclenchent, quelles propriétés utiliser, lesquelles éviter, et comment créer des raccourcis qui fonctionnent vraiment partout.
Les trois événements : keydown, keypress, keyup
Quand un utilisateur appuie sur une touche, le navigateur déclenche jusqu'à trois événements dans l'ordre suivant :
- keydown — se déclenche immédiatement à l'appui de la touche, avant l'insertion de caractère
- keypress — se déclenche après keydown, mais uniquement pour les touches produisant une valeur de caractère
- keyup — se déclenche au relâchement de la touche
En bref : utilisez keydown pour la plupart des cas. Voici pourquoi :
keypress est obsolète. Il ne se déclenchait jamais pour les touches non imprimables comme Escape, Delete, F1-F12 ou les touches fléchées. Si votre gestionnaire de raccourci ne fonctionnait que pour les touches alphabétiques, keypress en était probablement la cause. Ne l'utilisez pas dans du nouveau code.
keyup est utile quand vous voulez réagir spécifiquement après le relâchement d'une touche — comme mettre à jour un aperçu après la saisie d'un caractère. Mais pour les raccourcis et les contrôles de jeu, keydown offre un comportement plus rapide et prévisible.
keydown a aussi l'avantage de se déclencher à répétition quand une touche est maintenue (à la vitesse de répétition du clavier OS), ce qui est exactement ce que vous voulez pour le défilement ou les déplacements d'un personnage de jeu.
document.addEventListener('keydown', (e) => {
// C'est ici que vous voulez être
console.log(e.key, e.code);
});
Les propriétés qui comptent vraiment
Quand un KeyboardEvent se déclenche, l'objet événement contient de nombreuses propriétés. Voici celles que vous devez connaître.
key — Ce que la touche produit
key donne la valeur chaîne de ce que la touche représente dans le contexte actuel. Pour une touche alphabétique ordinaire, c'est le caractère lui-même : "a", "A" (avec Shift), "é" (sur un clavier français). Pour les touches spéciales, c'est un nom descriptif : "Enter", "Escape", "ArrowLeft", "F5", "Backspace".
C'est la propriété à utiliser en premier. Elle tient compte de la disposition et des modificateurs, et vous dit ce que la touche signifie pour l'utilisateur.
document.addEventListener('keydown', (e) => {
if (e.key === 'Enter') {
submitForm();
}
if (e.key === 'Escape') {
closeModal();
}
if (e.key === 'ArrowLeft') {
goToPreviousSlide();
}
});
Un point à noter : key est sensible à la casse et aux modificateurs. Appuyer sur a sans Shift donne "a". Avec Shift, cela donne "A". Si votre raccourci ne doit pas dépendre de la casse, normalisez :
if (e.key.toLowerCase() === 'k') {
openCommandPalette();
}
code — Quelle touche physique a été pressée
code donne l'identifiant de la position physique de la touche sur le clavier, indépendamment des modificateurs ou de la disposition du clavier. La touche en haut à gauche de la zone alphabétique est toujours "KeyQ" — même si la disposition de l'utilisateur place "A" là (comme sur un clavier AZERTY).
Le format est cohérent : les touches alphabétiques sont "KeyA" à "KeyZ", les touches numériques sont "Digit0" à "Digit9", les touches de fonction sont "F1" à "F12".
Utilisez code quand vous vous souciez de la position physique de la touche plutôt que de ce qu'elle produit. Le cas d'usage classique est les contrôles de jeu :
document.addEventListener('keydown', (e) => {
switch (e.code) {
case 'KeyW':
case 'ArrowUp':
player.moveUp();
break;
case 'KeyS':
case 'ArrowDown':
player.moveDown();
break;
case 'KeyA':
case 'ArrowLeft':
player.moveLeft();
break;
case 'KeyD':
case 'ArrowRight':
player.moveRight();
break;
}
});
Utiliser code signifie que les contrôles WASD fonctionnent de la même façon quelle que soit la disposition du clavier du joueur. Sur un clavier AZERTY, la touche W est à une position différente, donc e.key donnerait "z" — mais e.code retourne toujours "KeyW" car la position physique est la même.
keyCode et which — Héritage, obsolète, à éviter
keyCode et which sont l'ancienne méthode. Ils donnent un code numérique pour la touche — 65 pour A, 13 pour Enter, 27 pour Escape. Le problème est que ces valeurs n'étaient pas cohérentes, surtout pour la ponctuation et les touches spéciales. Différents navigateurs retournaient des nombres différents, basés sur des codes de touches virtuelles Windows qui n'avaient aucune signification intuitive.
La documentation MDN marque keyCode et which comme obsolètes. Ils existent encore pour la compatibilité ascendante, mais ne les utilisez pas dans du nouveau code.
Vieux code que vous pourriez encore voir :
// Ne faites pas ça
if (e.keyCode === 13) { /* Enter */ }
if (e.which === 27) { /* Escape */ }
Équivalent moderne :
// Faites plutôt ça
if (e.key === 'Enter') { /* Enter */ }
if (e.key === 'Escape') { /* Escape */ }
charCode — Seulement dans keypress, aussi obsolète
charCode était le point de code Unicode du caractère, mais il ne fonctionnait que dans les événements keypress, et uniquement pour les caractères imprimables. Puisque keypress lui-même est obsolète, charCode l'est doublement. Utilisez simplement e.key et appelez .codePointAt(0) si vous avez besoin de la valeur Unicode.
location — Pour les touches présentes à plusieurs endroits
location indique quelle instance d'une touche a été pressée, pour les touches présentes à plusieurs endroits du clavier. C'est un nombre : 0 est la position standard, 1 est le modificateur gauche, 2 est le modificateur droit, et 3 est le pavé numérique.
e.location === 1 avec e.key === "Shift" signifie que la touche Shift gauche a été pressée. e.location === 3 avec e.key === "5" signifie que le 5 du pavé numérique a été pressé.
Touches modificatrices : Ctrl, Shift, Alt, Meta
Pour les raccourcis clavier, vous combinez généralement une touche ordinaire avec un ou plusieurs modificateurs. L'objet événement a des propriétés booléennes pour chaque modificateur :
e.ctrlKey— Ctrl est maintenue.shiftKey— Shift est maintenue.altKey— Alt (ou Option sur Mac) est maintenue.metaKey— Meta est maintenu (Command sur Mac, touche Windows sur Windows)
document.addEventListener('keydown', (e) => {
// Ctrl+S (ou Cmd+S sur Mac)
if ((e.ctrlKey || e.metaKey) && e.key === 's') {
e.preventDefault(); // Empêche la boîte de dialogue Enregistrer du navigateur
saveDocument();
}
// Ctrl+Shift+P — palette de commandes
if ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key === 'p') {
e.preventDefault();
openCommandPalette();
}
// Alt+Left — retour
if (e.altKey && e.key === 'ArrowLeft') {
goBack();
}
});
Le modèle e.ctrlKey || e.metaKey est l'approche standard pour les raccourcis multiplateformes. Sur macOS, la plupart des raccourcis utilisent Command (metaKey). Sur Windows/Linux, ils utilisent Ctrl. Ce modèle gère les deux.
Le problème des claviers internationaux
Voici un scénario qui surprend beaucoup de développeurs : votre application a un raccourci clavier, disons Ctrl+/ pour basculer les commentaires. Vous le testez sur votre clavier en-US, ça fonctionne parfaitement. Un utilisateur en France remonte un bug — le raccourci ne fonctionne pas.
Sur un clavier AZERTY, le caractère / est souvent accessible via Shift+: ou une autre combinaison. Donc e.key quand on appuie sur cette position de touche est complètement différent de ce à quoi vous vous attendez.
Deux approches pour gérer cela :
Option 1 : Utiliser e.code pour les raccourcis basés sur la position
// La touche / sur un clavier US est à une position physique spécifique
// code retournera toujours 'Slash' pour cette position
if (e.ctrlKey && e.code === 'Slash') {
toggleComment();
}
Option 2 : Laisser les utilisateurs configurer leurs propres raccourcis
Des applications comme VS Code font cela bien — elles permettent de rebinder n'importe quel raccourci à la combinaison de touches de votre choix. Plus de travail à implémenter, mais la bonne réponse pour un outil professionnel avec une base d'utilisateurs internationale.
Accessibilité : la navigation clavier est importante
Si vous ajoutez des interactions clavier personnalisées à votre application, n'oubliez pas que la navigation clavier est une exigence d'accessibilité fondamentale. Les utilisateurs qui dépendent des lecteurs d'écran ou qui ne peuvent pas utiliser une souris dépendent de l'accès clavier.
Quelques points à garder à l'esprit :
Gestion du focus. Assurez-vous que les éléments interactifs sont focalisables (avec tabindex="0" si nécessaire) et que le focus se déplace logiquement au fil des changements d'interface. Quand vous ouvrez une modale, déplacez le focus à l'intérieur. Quand vous la fermez, renvoyez le focus à l'élément qui l'a déclenchée.
Ne piégez pas le focus (sauf dans les modales). Les utilisateurs doivent pouvoir naviguer dans l'interface avec Tab sans se bloquer.
Ne vous fiez pas uniquement aux raccourcis clavier. Les utilisateurs pourraient ne pas les découvrir. Fournissez des alternatives UI visibles pour chaque action.
Débogage avec le Keycode Viewer
Quand vous créez des interactions clavier, la partie la plus difficile est souvent de déterminer quelles valeurs le navigateur vous donne pour une frappe de touche spécifique. La documentation est utile, mais parfois vous avez juste besoin d'appuyer sur la touche et de voir la sortie.
C'est exactement ce que fait notre outil Keycode Viewer. Ouvrez-le, appuyez sur n'importe quelle touche, et il affiche immédiatement :
key— la valeur logiquecode— l'identifiant de position physiquekeyCode— la valeur numérique héritée (pour référence avec du vieux code)which— l'autre propriété héritéecharCode— le code de caractère des événements keypresslocation— standard/gauche/droite/pavé numériquectrlKey,shiftKey,altKey,metaKey— états des modificateurs
Particulièrement utile pour les claviers internationaux, les caractères spéciaux, ou pour comprendre pourquoi du code existant ne reconnaît pas une touche particulière.
Référence rapide
| Propriété | Utilisation | Obsolète ? |
|---|---|---|
key | Nom du caractère ou de l'action | Non |
code | Position physique de la touche | Non |
keyCode | Aucune — héritage uniquement | Oui |
which | Aucune — héritage uniquement | Oui |
charCode | Aucune — héritage uniquement | Oui |
ctrlKey | Vérifier si Ctrl est maintenu | Non |
shiftKey | Vérifier si Shift est maintenu | Non |
altKey | Vérifier si Alt/Option est maintenu | Non |
metaKey | Vérifier si Cmd/Win est maintenu | Non |
Le modèle mental principal : utilisez e.key en premier. Il vous dit ce que la touche signifie. Utilisez e.code uniquement quand la position physique compte spécifiquement (contrôles de jeu, raccourcis indépendants de la disposition). Ne jamais utiliser keyCode, which ou charCode dans du nouveau code.
Maîtrisez cela et vos interactions clavier seront cohérentes sur tous les navigateurs, dispositions de clavier et systèmes d'exploitation. Et vous cesserez de recevoir ces rapports de bug des utilisateurs Firefox.