Установка маски для поля телефона в форме

Чтобы пользователю было удобнее, добавим под полем номер телефона подсказку со счётчиком: сколько цифр введено и сколько осталось до полного 10-значного номера.

Ниже поля input для телефона вставим элемент <div> или <small> для подсказки.

HTML
<form action="" class="form">
    <!-- Поле для имени пользователя -->
    <input type="text" class="form__input" placeholder="Введите Имя" required>

    <!-- Контейнер для телефонного поля и подсказки -->
    <div class="phone-wrapper">
        <!-- Поле ввода телефона с id для JavaScript -->
        <input id="phone" type="tel" class="form__input" placeholder="+7(999) 888-77-66" required>
        <!-- Элемент для вывода подсказок и счётчика -->
        <small id="phone-help" class="phone-help"></small>
    </div>

    <!-- Кнопка отправки формы -->
    <button type="submit" class="form__button">
        Отправить
    </button>
</form>

Добавим CSS, чтобы:

  • При фокусе на поле менялся цвет рамки.
  • При невалидном номере (меньше 10 введённых цифр) поле подсвечивалось красным.

Здесь:

  • .form__input:focus — срабатывает автоматически при фокусе
  • .form__input.error — будет применяться из JavaScript, если номер введён неверно
  • .phone-wrapper даёт отступ снизу
  • .phone-help — серый текст подсказки
CSS
/* Базовая стилизация полей ввода */
.form__input {
    padding: 8px 12px;
    /* Внутренние отступы для комфортного ввода */
    font-size: 16px;
    /* Размер шрифта */
    border: 2px solid #ccc;
    /* Серая рамка по умолчанию */
    border-radius: 4px;
    /* Скругление углов */
    outline: none;
    /* Убираем стандартную подсветку браузера */
    transition: border-color 0.2s;
    /* Плавная анимация смены цвета рамки */
}

/* Подсветка рамки синим при фокусе */
.form__input:focus {
    border-color: #007bff;
    /* Оттенок синего */
}

/* Класс ошибки: красная рамка */
.form__input.error {
    border-color: #dc3545;
    /* Оттенок красного */
}

/* Обёртка для input и подсказки */
.phone-wrapper {
    position: relative;
    margin-bottom: 1.5em;
    /* Отступ снизу между полями формы */
}

/* Стиль текста подсказки под полем */
.phone-help {
    display: block;
    margin-top: 4px;
    font-size: 14px;
    color: #666;
    /* Тёмно-серый цвет */
}

Основной скрипт

При каждом вводе будем:

  • Извлекать только цифры из введённого значения
  • Строить строку в формате +7(XXX) XXX-XX-XX, подставляя цифры по порядку
  • Ограничивать ввод 10 цифрами (без кода страны)

Далее:

  1. Навесить обработчик focus на phoneInput, который:
    • Если value пусто, записывает '+7('
  2. Навесить обработчик blur на phoneInput, который:
    • Если после форматирования в поле осталось меньше трёх символов (то есть только префикс +7( или вообще пусто), очищает value

Чтобы очистка учитывала только пользовательский ввод, нужно перед проверкой также убрать ведущую «7» (код страны) точно так же, как в formatPhone:

  • Для '+7(' → raw = "7" → после удаления кода страны raw = "" → raw.length === 0 → поле очистится
  • Если пользователь ввёл «+7(9» → raw = "79" → после удаления «7» → raw = "9" → raw.length === 1 → поле не очистится, поскольку есть хотя бы одна цифра

Валидация номера при отправке формы

Добавим обработчик submit на форму, который:

  1. Снимает класс .error с поля.
  2. Проверяет, что после удаления всего, кроме цифр, и удаления ведущей «7» осталось ровно 10 цифр
  3. Если нет — отменяет отправку, добавляет .error и ставит фокус обратно

Логика подсчёта цифр номера в JavaScript

В уже существующий скрипт добавляем функцию updateHelp(), которая по phoneInput.value считает цифры (без кода страны) и выводит сообщение вида:

  • «Введено 4 из 10 цифр»
  • или «Осталось ввести 6 цифр»

Что получится:

  • Пока поле пустое, подсказка «Введите номер телефона».
  • При вводе цифр показывает прогресс.
  • При заполнении всех 10 цифр – «Номер введён полностью».
JavaScript
// Находим элементы: поле телефона и блок подсказки
const phoneInput = document.getElementById('phone');
const help = document.getElementById('phone-help');

// Форматирует строку в маску +7(XXX) XXX-XX-XX
function formatPhone(value) {
    // 1. Убираем все не-цифры
    let raw = value.replace(/\D/g, '');

    // 2. Если первым символом идёт '7' (код страны), удаляем его
    if (raw.charAt(0) === '7') {
        raw = raw.substring(1);
    }

    // 3. Берём первые 10 цифр пользовательского номера
    const digits = raw.substring(0, 10);
    const parts = [];

    // 4. Добавляем префикс +7
    parts.push('+7');

    // 5. Открывающая скобка и первые 3 цифры
    if (digits.length > 0) {
        parts.push('(' + digits.substring(0, Math.min(3, digits.length)));
    }
    // 6. Закрываем скобку после 3 цифр
    if (digits.length >= 3) {
        parts[1] += ')';
    }
    // 7. Следующие 3 цифры с пробелом
    if (digits.length > 3) {
        parts.push(' ' + digits.substring(3, Math.min(6, digits.length)));
    }
    // 8. Две цифры и дефис
    if (digits.length > 6) {
        parts.push('-' + digits.substring(6, Math.min(8, digits.length)));
    }
    // 9. Последние две цифры и дефис
    if (digits.length > 8) {
        parts.push('-' + digits.substring(8, 10));
    }

    // Собираем все части в итоговую строку
    return parts.join('');
}

// Обновляет текст подсказки под полем телефона
function updateHelp(value) {
    // Убираем не-цифры
    let raw = value.replace(/\D/g, '');
    // Удаляем ведущую '7'
    if (raw.charAt(0) === '7') {
        raw = raw.substring(1);
    }

    const count = raw.length;         // Сколько введено цифр
    const remaining = 10 - count;     // Сколько осталось

    if (count === 0) {
        help.textContent = 'Введите номер телефона';
    } else if (count < 10) {
        help.textContent = `Введено ${count} из 10 цифр. Осталось ${remaining}`;
    } else {
        help.textContent = 'Номер введён полностью';
    }
}

// Обработчик ввода: форматируем и обновляем подсказку
phoneInput.addEventListener('input', (e) => {
    const formatted = formatPhone(e.target.value);
    e.target.value = formatted;
    updateHelp(formatted);

    // Перенос курсора в конец строки
    const pos = e.target.value.length;
    e.target.setSelectionRange(pos, pos);
});

phoneInput.addEventListener('focus', (e) => {
    phoneInput.setSelectionRange(6, 6);
    if (!e.target.value) {
        e.target.value = '+7(';
        updateHelp(e.target.value);
        // Ставим курсор сразу после открывающей скобки
        e.target.setSelectionRange(3, 3);
    }
});

// Обработка Backspace для удаления цифр в скобках
phoneInput.addEventListener('keydown', (e) => {
    if (e.key === 'Backspace') {
        const start = phoneInput.selectionStart;
        // Если каретка стоит сразу после ')', переносим её внутрь скобок
        // Формат префикса: "+7(" — цифры начинаются с позиции 3
        // Через formatPhone: ")." на позиции 4
        if (start === 4) {
            e.preventDefault();               // Отменяем обычный Backspace
            // Перемещаем курсор внутрь скобок
            phoneInput.setSelectionRange(3, 3);
            // Удаляем символ перед новой позицией (цифру)
            const before = phoneInput.value.slice(0, 3);
            const after = phoneInput.value.slice(3);
            // Убираем первый символ после позиции 3, затем форматируем
            const newVal = before + after.substring(1);
            phoneInput.value = formatPhone(newVal);
            updateHelp(phoneInput.value);
            // Ставим каретку обратно в позицию 3
            phoneInput.setSelectionRange(3, 3);
        }
    }
});


// При потере фокуса: очищаем поле и подсказку, если нет цифр
phoneInput.addEventListener('blur', (e) => {
    let raw = e.target.value.replace(/\D/g, '');
    if (raw.charAt(0) === '7') {
        raw = raw.substring(1);
    }
    if (raw.length === 0) {
        e.target.value = '';
        help.textContent = '';
    }
});

// Валидация при отправке формы
const form = document.querySelector('.form');
form.addEventListener('submit', (e) => {
    phoneInput.classList.remove('error'); // Снимаем класс ошибки

    // Получаем только цифры без кода '7'
    let raw = phoneInput.value.replace(/\D/g, '');
    if (raw.charAt(0) === '7') {
        raw = raw.substring(1);
    }

    // Если не 10 цифр — отменяем отправку и подсвечиваем поле
    if (raw.length !== 10) {
        e.preventDefault();
        phoneInput.classList.add('error');
        phoneInput.focus();
    }
});

После добавления этого CSS и JavaScript тестируем форму:

  1. Клик по полю → рамка синяя
  2. Ввод меньше 10 цифр и отправка → поле красное, форма не уходит
  3. Ввод 10 цифр → форма успешно отправляется (или проходит валидация)

Есть некоторые ограничения при удалении (стирании) номера телефона, но это не критично. В противном случае лучше воспользоваться библиотекой inputmask.js:

HTML
<script src="https://unpkg.com/imask"></script>
<script>
  IMask(phoneInput, {mask: '+{7}(000) 000-00-00'});
</script>
Перейти к inputmask.js