GH GambleHub

Input masks and UX forms

1) Principles

1. Help, not punish. The mask guides input and reduces errors, but does not block printing and insertion.
2. Data ≠ display. We store "raw" normalized values, format only in UI.
3. Predictable cursor. Any auto-substitution does not "jump" caret or break undo/redo.
4. Locale and device. Keyboards, dividers, calendar and currencies - by region and platform.
5. Accessibility and privacy. Text + icon/color; we mask sensitive fields, but do not interfere with password managers/autocomplete.

2) When the mask is appropriate (and when not)

Use:
  • Formats with a stable structure: phone, IBAN, PAN (cards), CVC, date, time, index, OTP.
  • Monetary amounts with separators (when printing - "clean" input, when blur - format).
  • Codes (ref. codes, promo), fixed lengths.
Avoid:
  • Names/addresses/Email (mask limits valid characters/languages).
  • Complex free fields (comments, company names).
  • Input with potentially unknown format (international numbers without country).

3) Mask vs auto format vs validation

Mask - on-the-fly structure hint (brackets, hyphens); must not break the input/insertion.
Auto-format - use for blur/loss of focus (thousands, IBAN spaces).
Validation - correctness logic (length, checksums), showing errors after 'blur' or 'submit'.

Rule: the mask does not replace validation, and the auto-format should not change the meaning of the entered one.

4) HTML keyboards and attributes

Select the correct types/modes to speed up input and reduce errors:
Field`type``inputmode``autocomplete`Ad notata
Phone`tel``tel``tel`Shows the numeric keypad on mobile phones
Email`email``email``email`Format validation by browser
Sum`text``decimal``off`Local separators; store the number in cents
Date`date`/`text``numeric``bday`/`cc-exp`Native pickers where appropriate
PAN Card`text``numeric``cc-number`Tokenization; block logging
Holder name`text``latin`/`text``cc-name`Without autocap on desktop
IBAN`text``latin`/`text``off`Uppercase, no spaces in the value
OTP (6 digits)`text``numeric``one-time-code`SMS autocomplete on iOS/Android

5) Carriage, copy paste and normalization

Do not break caret: when auto-inserting characters (spaces/brackets), adjust the cursor position.
Copy paste: when inserting, clear spaces/hyphens → validate → display with formatting.
Normalization: trimming, replacement of "curves" of characters ('O'→'0' cannot be!), Translation to upper case for IBAN, unified storage date format (ISO).

PAN/IBAN normalization example:
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) Numbers, currencies and locales

Input "as printed" (tolerance ',' or '.' as separator), storage in minor units (kopecks/cents).
Locale mapping (grouping of thousands) on blur/after submission; in focus, show the "raw" value for ease of editing.
Explicitly specify the currency and fix the accuracy (for example, 2 characters).

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) Dates and times

If native pickers are uncomfortable/different on platforms - use a text box with a'DD mask. MM. YYYY ', but keep ISO' YYYY-MM-DD '.
Date reality check (29. 02, ranges), timezones - on the server.

Add buttons "Today," "Now," "Clear."

8) Phones and countries

Two fields: country (+ code) and number or smart mask for the selected country.
When inserting the full '+ CC...', autocomplete the country.
Store E.164 ('+ CCXXXXXXXXX'), show locally with spaces.

9) Payment details: PAN/IBAN/CVC/EXP

PAN: 4-4-4-4/4 grouping; in the value - only numbers; Luhn-check; no logs/analytics with PAN.
CVC:' password' -style (hidden), 'autocomplete =" cc-csc"', do not save to drafts.
EXP: 'MM/YY', auto-insert '/' after 2 digits, check range 01-12 and reasonable year.
IBAN: upper-case, spaces only in UI; Check length by country and checksum.

10) OTP/confirmation code

6 (or N) cells with autofocus and auto-transition, pasting from the buffer recognizes all the code.
'autocomplete =" one-time-code"', on mobile phones - auto-extraction from SMS.
Backup input without split fields (one field) - for screen readers.

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

11) Masks and a11y

Label is required ('<label for>'), placeholder is an example, not a replacement.
Explain the rule side by side: helper text with example ("Format: + CC ХХХ ХХХ-ХХ-ХХ").
Associate errors via 'aria-descripedby', critical - 'role = "alert"'.
The contrast of text and contours ≥ AA, ': focus-visible' cannot be hidden.

12) Privacy and security

Sensitive fields: do not log, do not write to RUM, do not save to drafts (PAN, CVC, passport).
Masks and formatting should not reveal the validity of the account ("If email is registered..." - neutral wording).
Idempotency and retry for critical submitts (payment/rate).

13) Form behavior and performance

Debit of asynchronous checks (250-400 ms), visible indication "Check...."

Do not lock the entire screen for the sake of one field; local spinner/skeleton.
Batch DOM changes; animate only 'transform/opacity'.
On mobile - avoid "jumps" when the keyboard appears (safe-area, viewport meta).

14) Code-snippets

Soft phone mask (without breakage of the insert):
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);
});
Amount: "raw in focus → format with blur":
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 and grouping under blur:
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) Design system tokens (example)

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 presets:
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) The specifics of iGaming

Payments/withdrawals: PAN/IBAN/amount with soft masks; strict idempotence and lack of sensitive field logs; tips about commissions and deadlines.
KYC: masks for dates, passport numbers (without "hard" filtering - taking into account different formats), file size/type, preview.
Limits and responsible play: understandable amounts/periods (days/weeks/months), helpers nearby, AAA contrast.
Bets: quick entry of the amount (presets + field), in focus "raw" number, when blurring format by locale; non-admission, ""...../of double separator.

17) Anti-patterns

Hard masks that deny valid characters/insertion.
Jumping caret with auto format; loss of extraction/undo.
Placeholder instead of label.
Auto-add currency inside the value (breaks copy paste).
Errors "per character" without debunking.
Localindependent formats in storage (store ISO/numbers).
Logging PAN/passport numbers and showing "too honest" reasons for rejection.

18) Metrics and experiments

Error rate by fields (before/after mask).
Time-to-Complete forms and resubmissions.
The proportion of failed inserts (copy paste) and rollbacks (undo).
CTR of hints/examples, proportion of autocompletes.
Abandon rate in payment step/ACC.

19) QA checklist

Input and caret

  • Pasting from the buffer does not break, spaces/hyphens are cleared correctly.
  • Caret remains predictable after auto-format.

Locale and format

  • Amounts allow ', '/'.'; storage in minor units.
  • Dates are parsed and validated; storage in ISO.

A11y

  • Labels and 'aria-describby' are connected; 'role = "alert"' for critical.
  • Contrast and focus rings correspond to AA.

Security

  • Sensitive fields are not logged/cached.
  • Idempotency and retry at critical steps.

UX

  • Placeholder - example, not label; helper nearby.
  • Masks do not prevent printing on mobile phones; correct keyboards ('inputmode').

20) Documentation in the design system

Компоненты: `MaskedInput`, `MoneyInput`, `PhoneInput`, `OtpInput`, `IbanInput`.
Mask tokens (lengths/patterns), caret/insert rules, number/date localization.
Guides for privacy (what not to log), availability and auto-format vs blur.
"Do/Don't" with real examples and before/after metrics.

Brief Summary

Masks and shapes are good when they speed up input, keep data clean and do not interfere. Format carefully, normalize at the entrance, store in stable forms, take into account locales and availability. The forms then become quick and straightforward - especially in sensitive payment, KYC and betting scenarios.

Contact

Get in Touch

Reach out with any questions or support needs.We are always ready to help!

Start Integration

Email is required. Telegram or WhatsApp — optional.

Your Name optional
Email optional
Subject optional
Message optional
Telegram optional
@
If you include Telegram — we will reply there as well, in addition to Email.
WhatsApp optional
Format: +country code and number (e.g., +380XXXXXXXXX).

By clicking this button, you agree to data processing.