[How2Tips] How to restrict allowed characters inside a text input in one line of code

Published At

7/21/2021

Recently I encountered a problem which is very generic : I had to prevent some characters insertion inside a text input. It avoids letting user filling input with unwanted characters, then asking them to correct by displaying an error. For example, in case of a telephone number.

It's a pretty common need, a trifle to implement with the right approach. If you wanna see the better solution directly, click here.

First attempt : keydown + preventDefault

On a keydown event, the input value is not updated yet with incoming character. Though, we have the opportunity to prevent its addition by calling Event.preventDefault() if it does not match our expectations.

Main problem is that we need to ensure we're not deactivating events that do not insert characters but are mandatory for navigation: moving focus with Tab, selecting input content with Ctrl + A, etc...

Also, as we filter character insertions key by key, we won't remove unwanted characters from a copy/paste.

// <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()
      }
    }
}

Second attempt : keyup + replace

It is way easier to implement on a keyup event. When the event is triggered, input value is already updated with incoming character. All we have to do then is to replace unwanted characters by an empty string in input value.

Problem is we see unwanted characters appears in the input, then being removed afterward. It's not really elegant...

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

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

Third attempt and adopted solution: oninput + replace

By bringing the previous solution on the oninput event, we got the advantages without the disadvantages : we can make a replace on the input value without it being visible by the user.

Easy to implement, invisible for the user, handle copy/paste : we got our solution !

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

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

P.S. : Don't forget to add a global flag (/g) on the replace regex to replace all unwanted characters after a copy/paste.

Written by

Louis
Louis Lebrault


Comments