Визуальная индикация валидности

В интерфейсах ввода данных визуальная обратная связь играет критическую роль, особенно в формах, где пользователь вводит структурированные значения: телефоны, даты, банковские реквизиты, коды идентификации. Библиотека Inputmask предоставляет инструменты не только для ограничения формата ввода, но и для интеграции с механизмами валидации, которые позволяют отображать состояние поля в реальном времени.

Принципы визуальной индикации в контексте Inputmask

Inputmask изначально решает задачу маскирования ввода, но не ограничивается этим. Поверх маски можно строить слой логической проверки, который определяет текущее состояние значения:

  • соответствует ли введённый текст маске полностью;
  • находится ли пользователь в процессе ввода корректного значения;
  • нарушены ли обязательные правила формата;
  • является ли значение потенциально завершённым.

На основе этих состояний формируется визуальная индикация, которая обычно выражается через CSS-классы, атрибуты или внешние обработчики событий.

Ключевая идея заключается в разделении двух уровней:

  • структурная корректность (соответствие маске);
  • семантическая валидность (логическая завершённость значения).

Inputmask работает на уровне структуры, а визуальная индикация строится вокруг событий библиотеки.


События, используемые для определения состояния поля

Для реализации индикации валидности используются события, которые Inputmask генерирует в процессе работы с полем ввода.

oncomplete

Срабатывает, когда пользователь полностью заполнил маску. Это состояние часто интерпретируется как «валидное значение введено».

Типичный сценарий:

  • маска телефонного номера заполнена полностью;
  • дата введена в корректном формате;
  • код подтверждения соответствует требуемой длине.

Логика обработки:

Inputmask({
  mask: "+7 (999) 999-99-99",
  oncomplete: function () {
    this.classList.add("is-valid");
    this.classList.remove("is-invalid");
  }
}).mask("#phone");

onincomplete

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

Используется для отображения состояния ошибки или предупреждения.

Inputmask({
  mask: "99/99/9999",
  onincomplete: function () {
    this.classList.add("is-invalid");
    this.classList.remove("is-valid");
  }
}).mask("#date");

oncleared

Вызывается при полном очищении поля. В визуальной логике часто используется для сброса всех состояний.

Inputmask({
  mask: "9999-9999-9999-9999",
  oncleared: function () {
    this.classList.remove("is-valid", "is-invalid");
  }
}).mask("#card");

Использование CSS-классов для отображения состояния

Наиболее распространённый способ визуальной индикации — управление классами элемента. Обычно применяются три состояния:

  • базовое (нейтральное);
  • валидное;
  • невалидное.

Пример базовой схемы:

.input {
  border: 1px solid #ccc;
  transition: border-color 0.2s ease;
}

.input.is-valid {
  border-color: #2ecc71;
  background-color: #f0fff4;
}

.input.is-invalid {
  border-color: #e74c3c;
  background-color: #fff5f5;
}

С точки зрения UX важно, что изменение состояния должно происходить не мгновенно при каждом символе, а после перехода Inputmask в устойчивое состояние (oncomplete или onincomplete).


Состояние частичной валидности

Inputmask поддерживает сценарий, в котором значение ещё не завершено, но уже соответствует допустимой структуре на текущем этапе ввода.

Например, при маске:

99-9999

ввод 12- уже частично соответствует структуре, но не является завершённым значением.

Для визуализации такого состояния часто используется третья категория:

  • is-dirty или is-partial

Пример расширенной логики:

Inputmask({
  mask: "99-9999",
  onincomplete: function () {
    this.classList.add("is-partial");
    this.classList.remove("is-valid");
  },
  oncomplete: function () {
    this.classList.add("is-valid");
    this.classList.remove("is-partial", "is-invalid");
  }
}).mask("#code");

Интеграция с нативной HTML-валидацией

Inputmask не заменяет встроенную HTML5-валидацию, а дополняет её. Это позволяет использовать стандартные механизмы браузера:

  • :valid
  • :invalid
  • required
  • pattern

Однако важно учитывать, что Inputmask может временно приводить поле в состояние, которое не проходит нативную проверку до завершения ввода.

Пример комбинированного подхода:

<input
  id="email"
  type="text"
  required
/>
Inputmask({
  mask: "*{1,20}@*{1,10}.aa",
  oncomplete: function () {
    this.setCustomValidity("");
    this.classList.add("is-valid");
  },
  onincomplete: function () {
    this.setCustomValidity("Поле заполнено не полностью");
    this.classList.add("is-invalid");
  }
}).mask("#email");

Здесь используется:

  • setCustomValidity для участия в HTML-валидации;
  • классы для визуальной индикации;
  • события Inputmask для определения состояния.

Реакция на событие input

Хотя Inputmask предоставляет собственные события, часто используется синхронизация с нативным событием input для обновления UI в реальном времени.

const el = document.querySelector("#phone");

Inputmask({
  mask: "+7 (999) 999-99-99"
}).mask(el);

el.addEventListener("input", function () {
  if (el.inputmask && el.inputmask.isComplete()) {
    el.classList.add("is-valid");
  } else {
    el.classList.remove("is-valid");
  }
});

Метод isComplete() позволяет определить, заполнена ли маска полностью.


Программное определение состояния маски

Inputmask предоставляет API для проверки состояния значения без необходимости отслеживания событий.

isComplete()

Возвращает логическое значение, отражающее завершённость ввода.

const im = Inputmask("9999 9999 9999 9999").mask("#card");

const el = document.querySelector("#card");

el.addEventListener("blur", function () {
  if (el.inputmask.isComplete()) {
    el.classList.add("is-valid");
  } else {
    el.classList.add("is-invalid");
  }
});

getmetadata() и контекст состояния

Хотя этот метод не относится напрямую к визуальной валидации, он может использоваться для уточнения логики отображения состояния. Например, разные маски могут иметь разные правила завершённости.


Состояния при динамических масках

При использовании динамических масок визуальная индикация становится сложнее, поскольку формат ввода может меняться в процессе набора.

Пример:

Inputmask({
  mask: ["999-999", "9999-9999"],
  keepStatic: true,
  oncomplete: function () {
    this.classList.add("is-valid");
  },
  onincomplete: function () {
    this.classList.remove("is-valid");
    this.classList.add("is-invalid");
  }
}).mask("#dynamic");

Особенность таких сценариев:

  • состояние валидности зависит от выбранной ветки маски;
  • визуальная индикация должна обновляться при каждом переключении.

Задержка обновления состояния (debounce-подход)

При интенсивном вводе мгновенное обновление классов может приводить к визуальному «дребезгу». Для стабилизации состояния используется отложенная проверка.

let timer;

const el = document.querySelector("#input");

Inputmask("99999").mask(el);

el.addEventListener("input", function () {
  clearTimeout(timer);

  timer = setTimeout(() => {
    if (el.inputmask.isComplete()) {
      el.classList.add("is-valid");
      el.classList.remove("is-invalid");
    } else {
      el.classList.add("is-invalid");
      el.classList.remove("is-valid");
    }
  }, 200);
});

Такой подход позволяет:

  • избежать частых перерисовок;
  • стабилизировать UX при быстром вводе;
  • уменьшить нагрузку на обработчики событий.

Визуальная индикация через атрибуты

Помимо CSS-классов, состояние может отражаться через атрибуты, что удобно для интеграции с UI-фреймворками.

Inputmask("99/99/9999").mask("#date");

document.querySelector("#date").addEventListener("blur", function () {
  this.setAttribute(
    "data-valid",
    this.inputmask.isComplete()
  );
});

CSS:

input[data-valid="true"] {
  border-color: #2ecc71;
}

input[data-valid="false"] {
  border-color: #e74c3c;
}

Согласованность визуального состояния и бизнес-логики

В сложных формах визуальная индикация должна быть синхронизирована с бизнес-валидацией. Inputmask обеспечивает только синтаксическую корректность, тогда как дополнительные проверки (например, проверка существования номера телефона или карты) выполняются отдельно.

Типичная архитектура:

  • Inputmask → форматирование;
  • фронтенд-валидация → визуальная индикация;
  • серверная проверка → окончательная достоверность.

Такое разделение предотвращает ложное ощущение валидности при корректном, но несуществующем значении.


Объединение нескольких источников состояния

В реальных приложениях визуальная индикация часто зависит от нескольких факторов:

  • состояние Inputmask;
  • результат кастомной проверки;
  • состояние отправки формы;
  • асинхронные проверки.

Пример комбинированной логики:

function updateState(el, isServerValid) {
  const isMaskValid = el.inputmask.isComplete();

  if (isMaskValid && isServerValid) {
    el.classList.add("is-valid");
    el.classList.remove("is-invalid");
  } else {
    el.classList.add("is-invalid");
    el.classList.remove("is-valid");
  }
}

Такая схема позволяет отделить ответственность и избежать противоречий между слоями проверки.