Inputmask часто используется не только как утилита для форматирования ввода, но и как слой интеграции между пользовательским интерфейсом и дизайн-системой. В современных интерфейсах маска поля ввода перестала быть чисто функциональным инструментом — она становится частью визуального языка продукта, подчиняется токенам, состояниям компонентов и правилам взаимодействия.
В дизайн-системах поле ввода рассматривается как компонент с чётко
определёнными состояниями: default, focus,
disabled, error, success,
warning. Маска ввода должна не конфликтовать с этими
состояниями, а дополнять их.
Inputmask работает на уровне DOM, изменяя значение поля, но не управляя стилями напрямую. Это создаёт разделение ответственности:
Ключевой принцип интеграции — маска не должна ломать семантику компонента.
Типичный подход — привязка событий Inputmask к CSS-классам компонента.
import Inputmask from "inputmask";
const el = document.querySelector(".input");
const mask = new Inputmask({
mask: "+7 (999) 999-99-99",
showMaskOnHover: false,
showMaskOnFocus: true
});
mask.mask(el);
Дальше добавляется слой синхронизации:
el.addEventListener("complete", () => {
el.classList.add("is-complete");
el.classList.remove("is-error");
});
el.addEventListener("incomplete", () => {
el.classList.add("is-incomplete");
});
В дизайн-системе эти классы обычно соответствуют токенам состояния:
is-complete → success stateis-error → error stateis-incomplete → neutral/active stateВажно, что Inputmask не навязывает структуру классов — она проектируется отдельно и должна быть согласована с системой токенов.
Современные дизайн-системы используют токены вместо фиксированных значений:
Inputmask косвенно влияет на токены через состояние компонента. Например, маска даты может переключать визуальное состояние в зависимости от валидности.
const setState = (el, state) => {
el.dataset.state = state;
};
el.addEventListener("complete", () => setState(el, "success"));
el.addEventListener("incomplete", () => setState(el, "default"));
CSS:
.input[data-state="success"] {
border-color: var(--color-success);
}
.input[data-state="error"] {
border-color: var(--color-danger);
}
Таким образом Inputmask становится триггером для переключения токенизированных состояний.
Одна из проблем интеграции — различие между реальным значением и отображаемой маской. Дизайн-система должна определять, как именно отображается placeholder, заполненные символы и плейсхолдерные сегменты.
Inputmask поддерживает параметры визуального поведения:
new Inputmask({
mask: "99-99-9999",
placeholder: "_",
showMaskOnHover: false,
showMaskOnFocus: true
});
В дизайн-системах часто требуется:
CSS может быть расширен через псевдоклассы и data-атрибуты:
.input:not(:focus) {
letter-spacing: 0.5px;
color: var(--color-text-muted);
}
.input:focus {
color: var(--color-text-primary);
}
Inputmask не зависит от темы, но его поведение влияет на визуальную
плотность интерфейса. Например, символы маски _ или
• должны быть адаптированы под контрастные темы.
Рекомендуется избегать фиксированных символов в пользу токенов:
new Inputmask({
mask: "9999 9999 9999 9999",
placeholder: "•"
});
В дизайн-системе placeholder должен быть частью токенов:
:root {
--mask-placeholder-color: rgba(0,0,0,0.3);
}
[data-theme="dark"] {
--mask-placeholder-color: rgba(255,255,255,0.4);
}
.input::placeholder {
color: var(--mask-placeholder-color);
}
В компонентах UI библиотек (React/Vue/Angular) Inputmask обычно внедряется через обёртки.
Пример React-интеграции:
import { useEffect, useRef } from "react";
import Inputmask from "inputmask";
export function MaskedInput(props) {
const ref = useRef(null);
useEffect(() => {
const im = new Inputmask(props.mask);
im.mask(ref.current);
}, [props.mask]);
return <input ref={ref} className="input" />;
}
В дизайн-системах это оборачивается в абстракцию компонента:
MaskedInputDateInputPhoneInputКаждый из них наследует визуальные токены, но имеет свою конфигурацию маски.
Ошибки маски часто возникают не на уровне Inputmask, а на уровне бизнес-логики. Поэтому важно разделять:
Пример:
el.addEventListener("complete", () => {
if (!isValidNumber(el.value)) {
el.classList.add("is-error");
}
});
В дизайн-системе ошибка должна быть визуально единообразной:
.input.is-error {
border-color: var(--color-error);
box-shadow: 0 0 0 2px var(--color-error-soft);
}
Разные дизайн-системы поддерживают несколько режимов плотности:
Inputmask влияет на плотность через:
new Inputmask({
mask: "9999 9999 9999 9999",
greedy: false
});
CSS адаптация:
.input {
padding: var(--space-sm);
font-size: var(--font-size-md);
}
[data-density="compact"] .input {
padding: var(--space-xs);
font-size: var(--font-size-sm);
}
В современных UI-архитектурах Inputmask редко работает изолированно. Он подключается к слоям валидации:
Роль Inputmask — обеспечить корректный формат до отправки.
const value = el.value.replace(/\s/g, "");
if (!schema.validate(value)) {
el.dataset.state = "error";
}
Дизайн-системы часто требуют предсказуемого поведения при вставке данных:
el.addEventListener("paste", () => {
setTimeout(() => {
if (el.inputmask?.isComplete()) {
el.classList.add("is-complete");
}
}, 0);
});
Inputmask автоматически нормализует вставку, но UI должен реагировать визуально:
Inputmask не управляет анимациями, но его события могут запускать transition слои дизайн-системы.
.input {
transition: border-color 120ms ease, box-shadow 120ms ease;
}
el.addEventListener("complete", () => {
el.classList.add("animate-success");
});
Ключевой принцип — анимация должна быть отделена от логики маски.
В зрелых системах Inputmask не используется напрямую. Он инкапсулируется:
export function createPhoneMask(el) {
return new Inputmask({
mask: "+7 (999) 999-99-99",
showMaskOnFocus: true
}).mask(el);
}
Это позволяет:
Такой слой становится частью дизайн-системы на уровне поведения, а не только стилей.