GH GambleHub

Маски ввода и UX-формы

1) Принципы

1. Помогать, не наказывать. Маска направляет ввод и снижает ошибки, но не блокирует печать и вставку.
2. Данные ≠ отображение. Храним «сырые» нормализованные значения, форматируем только в UI.
3. Предсказуемый курсор. Любая автоподстановка не «прыгает» caret и не ломает undo/redo.
4. Локаль и устройство. Клавиатуры, разделители, календарь и валюты — по региону и платформе.
5. Доступность и приватность. Текст + иконка/цвет; чувствительные поля маскируем, но не мешаем менеджерам паролей/автозаполнению.

2) Когда маска уместна (и когда нет)

Использовать:
  • Форматы с устойчивой структурой: телефон, IBAN, PAN (карты), CVC, дата, время, индекс, OTP.
  • Денежные суммы с разделителями (при печати — «чистый» ввод, при блюре — формат).
  • Коды (реф.коды, промо), фиксированные длины.
Избегать:
  • Имена/адреса/Email (маска ограничивает допустимые символы/языки).
  • Сложные свободные поля (комментарии, названия компаний).
  • Ввод с потенциально неизвестным форматом (международные номера без страны).

3) Маска vs автоформат vs валидация

Маска — подсказка структуры «на лету» (скобки, дефисы); не должна ломать ввод/вставку.
Автоформат — применяем при блюре/потере фокуса (тысячи, пробелы IBAN).
Валидация — логика корректности (длина, контрольные суммы), показ ошибок после `blur` или `submit`.

Правило: маска не заменяет валидацию, а автоформат не должен менять смысл введенного.

4) Клавиатуры и атрибуты HTML

Подберите корректные типы/режимы, чтобы ускорить ввод и снизить ошибки:
Поле`type``inputmode``autocomplete`Примечание
Телефон`tel``tel``tel`Показывает цифровую клавиатуру на мобилках
Email`email``email``email`Валидация формата браузером
Сумма`text``decimal``off`Локальные разделители; хранить число в «центах»
Дата`date`/`text``numeric``bday`/`cc-exp`Нативные пикеры там, где уместно
Карта PAN`text``numeric``cc-number`Токенизация; блокировать логирование
Имя держателя`text``latin`/`text``cc-name`Без автокапса на десктопе
IBAN`text``latin`/`text``off`Uppercase, без пробелов в значении
OTP (6 цифр)`text``numeric``one-time-code`Автозаполнение СМС на iOS/Android

5) Карет, копипаст и нормализация

Не ломать caret: при авто-вставке символов (пробелы/скобки) корректируйте позицию курсора.
Копипаст: при вставке очищайте от пробелов/дефисов → валидируйте → отображайте с форматированием.
Нормализация: тримминг, замена «кривых» символов (`O`→`0` нельзя!), перевод в верхний регистр для IBAN, единый формат даты в хранилище (ISO).

Пример нормализации PAN/IBAN:
js const clean = s => s. replace(/[^\da-zA-Z]/g,'');
const normalizePAN = s => clean(s). slice (0.19) ;//no spaces/hyphens const normalizeIBAN = s => clean (s). toUpperCase();   // A–Z0–9

6) Числа, валюты и локали

Ввод «как печатается» (допуск `,` или `.` как разделителя), хранение в minor units (копейки/центы).
Отображение по локали (группировка тысяч) на блюре/после сабмита; в фокусе показывайте «сырое» значение для удобства редактирования.
Явно указывайте валюту и фиксируйте точность (например, 2 знака).

js function parseMoney(input) {
//resolve both comma and period as decimal const s = input. replace(/\s/g,''). replace(',', '.');
const num = Number(s);
if (Number. isNaN(num)) return null;
return Math. round(num 100); // cents
}

function formatMoney(cents, locale='ru-RU', currency='RUB') {
return (cents/100). toLocaleString(locale, { style:'currency', currency });
}

7) Даты и время

Если нативные пикеры неудобны/разные на платформах — используйте текстовое поле с маской `DD.MM.YYYY`, но храните ISO `YYYY-MM-DD`.
Проверка реальности дат (29.02, диапазоны), таймзоны — на сервере.
Добавьте кнопки «Сегодня», «Сейчас», «Очистить».

8) Телефоны и страны

Два поля: страна (+код) и номер или «умная» маска по выбранной стране.
При вставке полного `+CC …` автозаполните страну.
Храните E.164 (`+CCXXXXXXXXX`), показывайте локально с пробелами.

9) Платежные реквизиты: PAN/IBAN/CVC/EXP

PAN: группировка 4-4-4-4/4; в значении — только цифры; Luhn-check; никаких логов/аналитики с PAN.
CVC: `password`-стиль (скрыто), `autocomplete="cc-csc"`, не сохранять в черновики.
EXP: `MM/YY`, авто-вставка `/` после 2 цифр, проверка диапазона 01–12 и разумного года.
IBAN: upper-case, пробелы только в UI; проверка длины по стране и контрольной суммы.

10) OTP/код подтверждения

6 (или N) ячеек с автофокусом и авто-переходом, вставка из буфера распознает весь код.
`autocomplete="one-time-code"`, на мобильных — автоизвлечение из СМС.
Бэкап-ввод без сплит-полей (одно поле) — для скринридеров.

html
<div class="otp" role="group" aria-label="Код из SMS">
<input inputmode="numeric" maxlength="1">
<input inputmode="numeric" maxlength="1">
<!-- … -->
</div>

11) Маски и a11y

Лейбл обязателен (`<label for>`), placeholder — пример, а не замена.
Объясняйте правило рядом: helper text с примером («Формат: +CC ХХХ ХХХ-ХХ-ХХ»).
Ошибки связывайте через `aria-describedby`, критичные — `role="alert"`.
Контраст текста и контуров ≥ AA, `:focus-visible` не скрывать.

12) Приватность и безопасность

Чувствительные поля: не логировать, не писать в RUM, не сохранять в черновики (PAN, CVC, паспорт).
Маски и форматирование не должны раскрывать валидность учетной записи («Если email зарегистрирован…» — нейтральная формулировка).
Идемпотентность и retry для критичных сабмитов (платеж/ставка).

13) Поведение форм и производительность

Дебаунс асинхронных проверок (250–400 мс), видимая индикация «Проверяем…».
Не блокируйте весь экран ради одного поля; локальный спиннер/скелет.
Батчите изменения DOM; анимируйте только `transform/opacity`.
На мобильных — избегайте «скачков» при появлении клавиатуры (safe-area, viewport meta).

14) Код-сниппеты

Мягкая маска телефона (без ломки вставки):
js function formatPhoneVisible(value) {
const d = value. replace(/\D/g,''). slice(0,15);
if (!d) return '';
if (d. startsWith('7')          d. startsWith('8')) {
return d. replace(/^([78])? (\d{3})(\d{3})(\d{2})(\d{2})./, '+7 ($2) $3-$4-$5');
}
// generic E.164 grouping: +CC XXX XXX XX XX return d. replace(/^(\d{1,3})(\d{0,3})(\d{0,3})(\d{0,2})(\d{0,2})./, (m,c1,c2,c3,c4,c5)=>
`+${c1}${c2?` ${c2}`:''}${c3?` ${c3}`:''}${c4?` ${c4}`:''}${c5?` ${c5}`:''}`.trim());
}

const input = document. querySelector('#phone');
input. addEventListener('input', e => {
const raw = e. target. value;
const pos = e. target. selectionStart;
const digitsBefore = raw. slice(0,pos). replace(/\D/g,''). length;
const cleaned = raw. replace(/[^\d+]/g,'');
const visible = formatPhoneVisible(cleaned);
e. target. value = visible;
// restore caret by counting digits let p = 0, count = 0;
while (p < e. target. value. length && count < digitsBefore) { if (/\d/.test(e. target. value[p])) count++; p++; }
e. target. setSelectionRange(p, p);
});
Сумма: «сырое в фокусе → формат при блюре»:
js const amount = document. getElementById('amount');
let cents = null;

amount. addEventListener('focus', () => {
if (cents!=null) amount. value = String(cents/100). replace('.', ',');
});
amount. addEventListener('blur', () => {
const v = parseMoney(amount. value) ;//from section 6 if (v = = null) return; cents = v;
amount. value = formatMoney(cents, 'ru-RU', 'RUB');
});
IBAN: upper-case и группировка при блюре:
js const iban = document. getElementById('iban');
iban. addEventListener('input', () => iban. value = iban. value. toUpperCase());
iban. addEventListener('blur', () => {
const raw = normalizeIBAN(iban. value);
iban. dataset. raw = raw ;//for iban submission. value = raw. replace(/(.{4})/g,'$1 '). trim () ;//view only
});

15) Токены дизайн-системы (пример)

json
{
"input": {
"radius": 10,
"height": { "sm": 36, "md": 40, "lg": 48 },
"gap": 8,
"icon": 16
},
"mask": {
"debounceMs": 300,
"otpLength": 6,
"moneyPrecision": 2,
"phoneMaxDigits": 15
},
"a11y": {
"focusRing": { "width": 2, "offset": 2 },
"contrastAA": true
}
}
CSS-пресеты:
css
.input { height:40px; padding:0 12px; border-radius:10px; }
.input:focus-visible { outline:2px solid var(--focus-ring); outline-offset:2px; }
.field-error { color: var(--role-danger); font-size:.875rem; margin-top:6px; }
.otp input { width:40px; text-align:center; }

16) Специфика iGaming

Платежи/выводы: PAN/IBAN/amount с мягкими масками; строгая идемпотентность и отсутствие логов чувствительных полей; подсказки про комиссии и сроки.
KYC: маски для дат, паспортных номеров (без «жесткой» фильтрации — учет разных форматов), размер/тип файла, предпросмотр.
Лимиты и ответственная игра: понятные суммы/периоды (дни/недели/месяцы), хелперы рядом, контраст AAA.
Ставки: быстрый ввод суммы (кнопки-пресеты + поле), в фокусе «сырое» число, при блюре формат по локали; недопуск «,…..»/двойного разделителя.

17) Анти-паттерны

Жесткие маски, запрещающие допустимые символы/вставку.
Прыгающий caret при автоформате; пропажа выделения/undo.
Placeholder вместо лейбла.
Авто-добавление валюты внутрь значения (ломает копипаст).
Ошибки «на каждый символ» без дебаунса.
Локалезависимые форматы в хранилище (храните ISO/числа).
Логирование PAN/паспортных номеров и показ «слишком честных» причин отклонения.

18) Метрики и эксперименты

Error rate по полям (до/после маски).
Time-to-Complete формы и повторные отправки.
Доля неудачных вставок (копипаст) и «откатов» (undo).
CTR подсказок/примеров, доля автозаполнений.
Abandon rate на шаге платежа/KYC.

19) QA-чек-лист

Ввод и caret

  • Вставка из буфера не ломается, пробелы/дефисы очищаются корректно.
  • Caret остается предсказуемым после автоформата.

Локаль и формат

  • Суммы допускают `,`/`.`; хранение в minor units.
  • Даты парсятся и валидируются; хранение в ISO.

A11y

  • Лейблы и `aria-describedby` подключены; `role="alert"` для критических.
  • Контраст и фокус-кольца соответствуют AA.

Безопасность

  • Чувствительные поля не логируются/не кэшируются.
  • Идемпотентность и retry на критичных шагах.

UX

  • Placeholder — пример, не лейбл; helper рядом.
  • Маски не препятствуют печати на мобильных; корректные клавиатуры (`inputmode`).

20) Документация в дизайн-системе

Компоненты: `MaskedInput`, `MoneyInput`, `PhoneInput`, `OtpInput`, `IbanInput`.
Токены масок (длины/шаблоны), правила caret/вставки, локализация чисел/дат.
Гайды по приватности (чего не логировать), по доступности и по автоформату vs блюр.
«Do/Don’t» с реальными примерами и метриками до/после.

Краткое резюме

Маски и формы хороши, когда они ускоряют ввод, сохраняют данные чистыми и не мешают. Форматируйте бережно, нормализуйте на входе, храните в стабильных видах, учитывайте локали и доступность. Тогда формы становятся быстрыми и понятными — особенно в чувствительных сценариях платежей, KYC и ставок.

Contact

Свяжитесь с нами

Обращайтесь по любым вопросам или за поддержкой.Мы всегда готовы помочь!

Начать интеграцию

Email — обязателен. Telegram или WhatsApp — по желанию.

Ваше имя необязательно
Email необязательно
Тема необязательно
Сообщение необязательно
Telegram необязательно
@
Если укажете Telegram — мы ответим и там, в дополнение к Email.
WhatsApp необязательно
Формат: +код страны и номер (например, +380XXXXXXXXX).

Нажимая кнопку, вы соглашаетесь на обработку данных.