
⚙️ Как запретить ввод ненужных символов в 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. Первый блокирует нажатия, второй чистит последствия вставки. Универсальная функция-шаблон из раздела выше адаптируется под любое поле за минуту.
Главное правило, не блокируйте вставку целиком. Это бесит пользователей и не даёт реальной защиты. Чистите результат после вставки, а не запрещайте её.



