Block Special Characters in Input: From Regex to Native Validation
My 2015 Stack Overflow answer used keypress events to filter characters. In 2026, the input event and native validation do it better.
Block Special Characters in Input: From Regex to Native Validation
In 2015, I answered a question on Stack Overflow in Portuguese about how to restrict input fields to only accept certain characters. It scored 14 upvotes — a common problem with a deceptively tricky solution.
The original approach worked. But it had a blind spot that took years for the community to fully appreciate.
The 2015 Approach: Catching Keystrokes
Back then, the standard pattern was intercepting the keypress event and checking each character against an allowed list:
// 2015: Block characters at the keystroke level
input.onkeypress = function (e) {
var char = String.fromCharCode(e.which || e.keyCode);
var allowed = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
if (allowed.indexOf(char) === -1) {
e.preventDefault();
}
};
Or using a regex:
input.onkeypress = function (e) {
var char = String.fromCharCode(e.which);
if (!/[a-zA-Z0-9]/.test(char)) {
e.preventDefault();
}
};
It felt satisfying. Type a special character, nothing happens. Clean, immediate feedback.
The Problem Nobody Mentioned
Keypress-based filtering has a fundamental flaw: it only catches keyboard input. In 2015, that covered most cases. But users can also:
- Paste text with Ctrl+V or right-click paste
- Drag and drop text into the field
- Use autofill from the browser or password managers
- Use speech input or dictation
- Use on-screen keyboards on mobile devices
- Use IME (Input Method Editor) for Asian languages
None of these trigger keypress. Your carefully filtered input field would happily accept any character through these methods.
The 2026 Approach: Clean the Value, Don’t Block the Input
Modern input filtering uses the input event, which fires regardless of how the value changed:
// 2026: Clean the value on any change
input.addEventListener('input', () => {
input.value = input.value.replace(/[^a-zA-Z0-9]/g, '');
});
This catches everything — keyboard, paste, autofill, speech, drag-and-drop. Instead of blocking the character before it appears, it removes invalid characters immediately after the value changes.
Native HTML Validation
For many cases, you don’t need JavaScript at all:
<!-- Only allow letters and numbers, validated on submit -->
<input type="text" pattern="[a-zA-Z0-9]+" title="Letters and numbers only" required />
<!-- Hint mobile keyboards to show numeric layout -->
<input type="text" inputmode="numeric" pattern="[0-9]*" />
The pattern attribute validates on form submission. The inputmode attribute suggests which keyboard layout mobile browsers should show — without restricting what the user can type.
Custom Validation Messages
For a better UX, combine the input event with the Constraint Validation API:
input.addEventListener('input', () => {
if (/[^a-zA-Z0-9]/.test(input.value)) {
input.setCustomValidity('Only letters and numbers are allowed');
} else {
input.setCustomValidity('');
}
});
This gives you native browser validation styling and screen reader support for free.
The Key Takeaway
Don’t block keystrokes — validate and clean the input value. The keypress event was a product of its time, when keyboards were the only input method that mattered. The input event reflects the reality that text enters fields through dozens of channels.
And always remember: client-side validation is for UX. Server-side validation is for security. No amount of JavaScript filtering replaces validating on the server.
Related Posts
Block Special Characters in Input: From Regex to Native Validation
My 2015 Stack Overflow answer used keypress events to filter characters. In 2026, the input event and native validation do it better.
Check Email via AJAX Before Submit: From jQuery Blur to Fetch and Security Tradeoffs
From a 2016 Stack Overflow answer on checking email availability with jQuery AJAX to 2026 — fetch, AbortController, debouncing, and why user enumeration is a real risk.
Delete Table Rows Dynamically with JavaScript
My 2016 Stack Overflow answer used parentNode.removeChild to delete rows. In 2026, element.remove() and closest() made it a one-liner.