
⚙️ Як заборонити введення непотрібних символів в INPUT на JavaScript
Форма реєстрації, поле телефону, пошук за каталогом, користувач тицяє в INPUT і друкує що завгодно. Літери там, де очікуєш цифри. Спецсимволи в номері замовлення. Емодзі в полі email'у. Результат, сміття в базі, биті запити, валідація на бекенді падає з помилкою.
Проблема вирішується на фронті за 15 рядків коду. Без плагінів, без бібліотек, чистим JavaScript або парою HTML-атрибутів. Далі, три робочі підходи: від швидкого HTML5 до тонкої фільтрації на keydown, з готовими прикладами під типові сценарії.
💡 Швидкий огляд:
- Розбираємо, коли вистачає HTML-атрибутів
pattern,inputmodeіtype, а коли потрібен JavaScript - Пишемо фільтр «тільки цифри» на jQuery і чистому JS, обидва варіанти з порядковим розбором
- Додаємо захист від вставлення через Ctrl+V і контекстне меню
- Збираємо універсальну функцію-шаблон під будь-які обмеження: літери, латиниця, кастомна маска
HTML5: що можна зробити без жодного рядка JavaScript
Найпростіший і найнадійніший спосіб обмежити введення: сказати браузеру, що саме ви очікуєте в полі. Сучасні браузери розуміють три ключові атрибути, які закривають більшість типових задач.
type, первинний фільтр. type="number" дозволяє тільки цифри, мінус і десятковий роздільник. type="tel" на мобільних пристроях показує цифрову клавіатуру. type="email" перевіряє наявність @ під час надсилання форми. type="url" вимагає протокол. Це не блокує введення повністю, але дає правильну екранну клавіатуру і базову валідацію під час submit.
pattern, регулярний вираз на полі. Атрибут приймає regex і валідує значення під час надсилання форми:
1 <input type="text" pattern="[0-9]{6}" placeholder="Шесть цифр" title="Ровно 6 цифр">
Браузер блокує submit, якщо значення не збігається з шаблоном. Мінус: pattern не заважає вводити недозволені символи, він тільки перевіряє результат. Користувач може надрукувати «abc», і помилку побачить лише під час спроби надіслати форму.
inputmode, правильна клавіатура на мобільних. inputmode="numeric" відкриває цифрову клавіатуру, але не забороняє введення літер. inputmode="decimal" додає роздільник. Корисно у зв'язці з JavaScript-фільтром: клавіатура вже правильна, а JS добирає решту.
Що вибрати. Якщо потрібно саме заборонити введення недозволеного символу в реальному часі, HTML-атрибутів недостатньо. Йдемо в JavaScript.
JavaScript: блокування натискань через keydown
Підхід із keydown ловить кожне натискання клавіші до того, як символ з'явиться в полі. Якщо клавіша не в білому списку, event.preventDefault() гасить її.
Варіант 1: jQuery, тільки цифри
Код вішається на INPUT за id, дозволяє цифри і службові клавіші (backspace, стрілки, Tab), все інше ріжеться:
1 $(document).ready(function() { 2 $("#phone_input").keydown(function(event) { 3 // Служебные клавиши — пропускаем 4 if (event.keyCode === 46 || event.keyCode === 8 || 5 event.keyCode === 9 || event.keyCode === 27 || 6 (event.keyCode === 65 && event.ctrlKey === true) || 7 (event.keyCode >= 35 && event.keyCode <= 39)) { 8 return; 9 } 10 // Блокируем всё кроме цифр (основной блок и numpad) 11 if ((event.keyCode < 48 || event.keyCode > 57) && 12 (event.keyCode < 96 || event.keyCode > 105)) { 13 event.preventDefault(); 14 } 15 }); 16 });
Що тут відбувається порядково: keyCode 46 (Delete), 8 (Backspace), 9 (Tab), 27 (Escape), 65 + Ctrl (виділити все), 35..39 (Home, End, стрілки). Далі йдуть цифри основного блоку 48..57 (0..9) і numpad 96..105. Все, що не потрапило в ці діапазони,, preventDefault.
Повна таблиця кодів клавіш, на Cambia Research.
Варіант 2: чистий JavaScript, тільки цифри
Те саме, без jQuery, через onkeypress. Цей варіант компактніший і не тягне бібліотеку:
1 document.getElementById("phone_input").onkeypress = function(event) { 2 event = event || window.event; 3 if (event.charCode && (event.charCode < 48 || event.charCode > 57)) { 4 return false; 5 } 6 };
charCode перевіряє, що в події є друкований символ, службові клавіші (стрілки, backspace) проходять автоматично, charCode у них дорівнює 0. Цифри: 48..57, решта, return false.
Важливо: keyCode вважається застарілим (deprecated). У сучасному коді краще використовувати event.key, він повертає рядок із назвою клавіші і не залежить від розкладки:
1 element.addEventListener("keydown", function(event) { 2 // Разрешаем цифры, Backspace, Delete, стрелки, Tab 3 const allowedKeys = [ 4 "Backspace", "Delete", "Tab", "Escape", 5 "ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", 6 "Home", "End" 7 ]; 8 if (allowedKeys.includes(event.key)) return; 9 // Ctrl+A / Ctrl+C / Ctrl+V 10 if (event.ctrlKey) return; 11 // Только цифры 12 if (!/^[0-9]$/.test(event.key)) { 13 event.preventDefault(); 14 } 15 });
Підхід з event.key читається простіше і не вимагає запам'ятовувати числові коди. Але для підтримки старих браузерів keyCode-версія вище все ще працює.
Блокування вставлення: ловимо Ctrl+V і контекстне меню
keydown ловить натискання клавіш, але користувач може вставити текст через Ctrl+V або правий клік → «Вставити». Скопіював «abc123» у поле для цифр, і половина проскочила.
Рішення, подія input. Вона спрацьовує після БУДЬ-ЯКОЇ зміни значення поля: ручне введення, вставлення, автозаповнення, перетягування тексту. Фільтруємо підсумкове значення за регулярним виразом:
1 document.getElementById("digits_only").addEventListener("input", function(event) { 2 this.value = this.value.replace(/[^0-9]/g, ""); 3 });
Все. Один рядок, і через поле не пройде жодна не-цифра, незалежно від того, як вона туди потрапила. Для літер: replace(/[^a-zA-Zа-яА-ЯёЁ]/g, ""). Для латиниці: replace(/[^a-zA-Z]/g, "").
Комбінований підхід, золота середина. keydown дає миттєвий зворотний зв'язок (клавіша «не натискається»), а input страхує від вставлення. Ставте обидва обробники:
1 const field = document.getElementById("digits_only"); 2 3 field.addEventListener("keydown", function(event) { 4 const allowed = ["Backspace", "Delete", "Tab", "Escape", 5 "ArrowLeft", "ArrowRight", "Home", "End"]; 6 if (allowed.includes(event.key)) return; 7 if (event.ctrlKey) return; 8 if (!/^[0-9]$/.test(event.key)) event.preventDefault(); 9 }); 10 11 field.addEventListener("input", function() { 12 this.value = this.value.replace(/[^0-9]/g, ""); 13 });
Перший обробник ріже недозволені натискання миттєво. Другий, чистить хвости після вставлення й автозаповнення.
Готовий шаблон під будь-які обмеження
Зберемо функцію, яка приймає INPUT і регулярний вираз дозволених символів. Підійде для телефону, поштового індексу, логіна, пошуку за артикулом:
1 function restrictInput(element, allowedPattern) { 2 element.addEventListener("keydown", function(event) { 3 const serviceKeys = [ 4 "Backspace", "Delete", "Tab", "Escape", 5 "ArrowLeft", "ArrowRight", "Home", "End" 6 ]; 7 if (serviceKeys.includes(event.key)) return; 8 if (event.ctrlKey && ["a", "c", "v", "x", "z"].includes(event.key.toLowerCase())) return; 9 if (!allowedPattern.test(event.key)) event.preventDefault(); 10 }); 11 12 element.addEventListener("input", function() { 13 // Собираем глобальный паттерн из переданного и чистим 14 const globalPattern = new RegExp( 15 allowedPattern.source.replace("^", "").replace("$", ""), 16 "g" 17 ); 18 // Удаляем всё, что НЕ подходит под паттерн 19 const inverted = new RegExp( 20 "[^" + allowedPattern.source.slice(1, -1) + "]", "g" 21 ); 22 this.value = this.value.replace(inverted, ""); 23 }); 24 }
Використання:
1 // Только цифры 2 restrictInput(document.getElementById("phone"), /^[0-9]$/); 3 // Только латиница без пробелов 4 restrictInput(document.getElementById("login"), /^[a-zA-Z]$/); 5 // Буквы и цифры 6 restrictInput(document.getElementById("postal"), /^[a-zA-Z0-9]$/);
Функція не залежить від jQuery, працює в усіх сучасних браузерах і покриває три сценарії: ручне введення (keydown), вставлення (input), автозаповнення (input).
Зверніть увагу: keydown не спрацьовує на віртуальних клавіатурах деяких мобільних пристроїв, там input залишається єдиною страховкою. Тому два обробники у зв'язці — це не надмірність, а необхідність.
Відео вище, розбір валідації форм на чистому JavaScript від Web Dev Simplified. Охоплює вбудовані Constraint Validation API, кастомні повідомлення про помилки і стилізацію невалідних полів, гарне доповнення до описаних тут підходів.
⁉️🤔 Часті запитання
Чому не використовувати просто type="number"?
type="number"дозволяє введенняeіE(експонента), плюса, мінуса і крапки. Все це валідні символи для чисел із рухомою комою та експоненційного запису. Для поля телефону або поштового індексу вони зайві. Плюс браузери по-різному обробляють нечислове введення: одні мовчки пропускають, інші показують помилку тільки під час submit.
Чи можна повністю заблокувати вставлення через Ctrl+V?
Блокувати вставлення повністю, погана практика. Це ламає користувацький досвід і не захищає від інших способів вставлення (контекстне меню, перетягування). Правильний підхід: дозволити вставлення, але негайно очистити результат через
input-обробник, як показано в розділі вище.
Що робити з автозаповненням браузера?
Автозаповнення спрацьовує до
keydownіinput, браузер вставляє значення напряму. Обробникinputперехоплює і цей випадок: значення з'являється в полі, а потім одразу фільтрується. Якщо автозаповнення заважає (підставляє літери в поле телефону), додайте до INPUT атрибутautocomplete="off".
Чи працює це на мобільних пристроях?
Так, але із застереженням: віртуальні клавіатури не завжди генерують
keydownз очікуванимиkeyCodeіkey. Обробникinputпрацює стабільно скрізь. На мобільних ставтеinputmode="numeric"абоinputmode="decimal"на INPUT, користувач отримає правильну клавіатуру, навіть якщоkeydown-фільтр не спрацює.
Як заборонити пробіли?
Додайте пробіл у клас недозволених символів:
replace(/[^0-9a-zA-Z]/g, "")прибирає все, крім цифр і латиниці, включно з пробілами. Або явно:this.value = this.value.replace(/\s/g, "")видалить усі пробіли, табуляції та перенесення рядків.
Який підхід вибрати під вашу задачу

Якщо форма проста і критичної шкоди від пари невірних символів немає, беріть HTML5: type, pattern і inputmode закриють базові сценарії без жодного рядка JS. Швидко, нативно, жодних залежностей.
Якщо важливий контроль у реальному часі та миттєва реакція на кожне натискання, ставте зв'язку keydown + input. Перший блокує натискання, другий чистить наслідки вставлення. Універсальна функція-шаблон із розділу вище адаптується під будь-яке поле за хвилину.
Головне правило, не блокуйте вставлення повністю. Це дратує користувачів і не дає реального захисту. Чистьте результат після вставлення, а не забороняйте її.



