Comment limiter les caractères autorisés dans un input en une ligne de code ?

Publié le

31 août 2023

Récemment, j'ai rencontré un problème courant : je devais empêcher l'insertion de certains caractères à l'intérieur d'un input. Il s'agit d'éviter de laisser l'utilisateur insérer des caractères non désirés pour ensuite lui demander de corriger en affichant une erreur. Par exemple, dans le cas d'un numéro de téléphone.

C'est une bricole à mettre en oeuvre avec la bonne approche. Si vous voulez voir la meilleure solution directement, cliquez ici.

Première tentative : keydown + preventDefault

Lors d'un événement keydown, la valeur d'entrée n'est pas encore mise à jour avec le caractère entrant. Cependant, nous avons la possibilité d'empêcher son ajout en appelant Event.preventDefault() s'il ne correspond pas à nos attentes.

Le problème principal est que nous devons nous assurer que nous ne désactivons pas les événements qui n'insèrent pas de caractères mais qui sont obligatoires pour la navigation : déplacer le focus avec Tab, sélectionner le contenu d'une entrée avec Ctrl + A, etc...

De plus, comme nous filtrons les insertions de caractères touche par touche, nous ne supprimerons pas les caractères non désirés d'un copier/coller.

```
// <input onkeydown=onKeyDown(event) />

const onKeyDown = event => {
      const alwaysAllowed = [
        'Backspace',
        'Tab',
        'Enter',
        'ArrowUp',
        'ArrowDown',
        'ArrowLeft',
        'ArrowRight',
        'Home',
        'End',
        'PageUp',
        'PageDown',
        'Delete',
      ]

      if (
        !event.ctrlKey &&
        !event.altKey &&
        !alwaysAllowed.includes(event.key) &&
        !/[^0-9+]/g.test(event.key)
      ) {
        event.preventDefault()
      }
    }
}
```

Deuxième tentative : keyup + replace

Il est beaucoup plus facile de mettre en œuvre un événement keyup. Lorsque l'événement est déclenché, l'input est déjà mise à jour avec le caractère entrant. Tout ce que nous avons à faire alors est de remplacer les caractères indésirables par une chaîne vide dans la valeur d'entrée.

Le problème est que nous voyons des caractères indésirables apparaître dans l'entrée, puis être supprimés par la suite. Ce n'est pas très élégant...

// <input onkeyup=onKeyUp(event) />

const onKeyUp = event => {
    event.target.value = event.target.value.replace(/[^0-9+]/g, '')
}
onkeyup-restrictive-input.gif

Troisième tentative et solution adoptée : oninput + replace

En amenant la solution précédente sur l'événement oninput, nous avons obtenu les avantages sans les inconvénients : nous pouvons faire un remplacement sur la valeur d'entrée sans que cela soit visible par l'utilisateur.

Facile à mettre en place, invisible pour l'utilisateur, gestion du copier/coller : nous avons notre solution !

// <input oninput=onInput(event) />

const onInput = event => {
    event.target.value = event.target.value.replace(/[^0-9+]/g, '')
}

P.S. : N'oubliez pas d'ajouter un flag global (/g) à la regex de remplacement pour remplacer tous les caractères indésirables après un copier/coller.

Publié par

Louis Lebrault
Louis Lebrault

Self taught, Louis is now an experienced web developer. He discovered his passion for functional programming languages, especially Haskell.

Commentaires