Skip to content

Всё для WordPress, веб-разработки — и не только

⚙️ Как запретить ввод ненужных символов в INPUT на JavaScript

⚙️ Как запретить ввод ненужных символов в 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 &lt; 48 || event.keyCode &gt; 57) &&
12 (event.keyCode &lt; 96 || event.keyCode &gt; 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. Этот вариант компактнее и не тянет библиотеку:

1document.getElementById("phone_input").onkeypress = function(event) {
2 event = event || window.event;
3 if (event.charCode && (event.charCode &lt; 48 || event.charCode &gt; 57)) {
4 return false;
5 }
6};

charCode проверяет, что у события есть печатный символ, служебные клавиши (стрелки, backspace) проходят автоматически, charCode у них равен 0. Цифры: 48..57, остальное return false.

Важно: keyCode считается устаревшим (deprecated). В современном коде лучше использовать event.key, он возвращает строку с названием клавиши и не зависит от раскладки:

1element.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. Оно срабатывает после ЛЮБОГО изменения значения поля: ручной ввод, вставка, автозаполнение, перетаскивание текста. Фильтруем итоговое значение по регулярному выражению:

1document.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 страхует от вставки. Ставьте оба обработчика:

1const field = document.getElementById("digits_only");
2
3field.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
11field.addEventListener("input", function() {
12 this.value = this.value.replace(/[^0-9]/g, "");
13});

Первый обработчик режет неразрешённые нажатия мгновенно. Второй, чистит хвосты после вставки и автозаполнения.

Готовый шаблон под любые ограничения

Соберём функцию, которая принимает INPUT и регулярное выражение разрешённых символов. Подойдёт для телефона, почтового индекса, логина, поиска по артикулу:

1function 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// Только цифры
2restrictInput(document.getElementById("phone"), /^[0-9]$/);
3// Только латиница без пробелов
4restrictInput(document.getElementById("login"), /^[a-zA-Z]$/);
5// Буквы и цифры
6restrictInput(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. Первый блокирует нажатия, второй чистит последствия вставки. Универсальная функция-шаблон из раздела выше адаптируется под любое поле за минуту.

Главное правило, не блокируйте вставку целиком. Это бесит пользователей и не даёт реальной защиты. Чистите результат после вставки, а не запрещайте её.