Try any number
Paste an IBAN, an Emirates ID, a CNIC or a VAT number and see the whole answer — including whether a check digit was actually verified.
<div class="demo">
<div class="demo-grid-2">
<div class="demo-field">
<label class="demo-label" for="kind">What is it</label>
<select id="kind" class="demo-input"></select>
</div>
<div class="demo-field">
<label class="demo-label" for="value">The number</label>
<input id="value" class="demo-input" autocomplete="off" spellcheck="false">
<span class="demo-hint" id="hint"></span>
</div>
</div>
<div class="demo-row">
<button class="demo-btn" id="example">Give me a valid one</button>
<button class="demo-btn" id="break">Change a digit</button>
</div>
<p class="demo-out" id="verdict">Type something.</p>
<pre class="demo-out" id="detail"></pre>
</div>
import { generate, kinds, mask, validate } from 'https://www.devix.pk/cdn/oss/validators@1.0.0/index.js';
const LABELS = {
iban: 'IBAN (any country)',
vat: 'VAT number (Europe)',
'emirates-id': 'Emirates ID',
'uae-trn': 'UAE TRN',
'saudi-id': 'Saudi ID or Iqama',
'saudi-vat': 'Saudi VAT number',
'qatar-id': 'Qatar ID',
'kuwait-id': 'Kuwait Civil ID',
'bahrain-cpr': 'Bahrain CPR',
'oman-id': 'Oman civil number',
cnic: 'Pakistani CNIC',
ntn: 'Pakistani NTN',
pan: 'Indian PAN',
gstin: 'Indian GSTIN',
};
const MESSAGES = {
empty: 'Nothing typed yet.',
'too-short': 'Too short — check you copied all of it.',
'too-long': 'Too long.',
'bad-characters': 'There are characters in there that do not belong.',
'bad-structure': 'The length is right but the shape is wrong.',
'bad-checksum': 'A digit is wrong: the check digit disagrees. Almost always a typo.',
'unknown-country': 'No rules here for that country.',
};
const kindField = document.getElementById('kind');
const valueField = document.getElementById('value');
const hint = document.getElementById('hint');
const verdict = document.getElementById('verdict');
const detail = document.getElementById('detail');
for (const kind of kinds()) {
const option = document.createElement('option');
option.value = kind;
option.textContent = LABELS[kind] ?? kind;
kindField.append(option);
}
function check() {
const kind = kindField.value;
const result = validate(kind, valueField.value);
hint.textContent = mask(kind) ? `Looks like ${mask(kind)}` : '';
if (!valueField.value.trim()) {
verdict.textContent = 'Type something, or ask for an example.';
verdict.dataset.state = '';
detail.textContent = '';
return;
}
if (result.valid) {
// The important distinction: a verified check digit, or only the right shape.
const verified = result.checked === 'checksum';
verdict.textContent = verified ? '✓ Valid — the check digit agrees' : '✓ Looks right — but this number has no check digit to verify';
verdict.dataset.state = verified ? 'valid' : 'structure';
} else {
verdict.textContent = `✗ ${MESSAGES[result.reason] ?? result.reason}`;
verdict.dataset.state = 'invalid';
}
detail.textContent = JSON.stringify(result, null, 2);
}
document.getElementById('example').addEventListener('click', () => {
const kind = kindField.value;
valueField.value = kind === 'vat' ? 'DE136695976' : generate(kind);
check();
});
document.getElementById('break').addEventListener('click', () => {
const digits = [...valueField.value];
const at = digits.findLastIndex((char) => /\d/.test(char));
if (at < 0) return;
digits[at] = String((Number(digits[at]) + 1) % 10);
valueField.value = digits.join('');
check();
});
kindField.addEventListener('change', check);
valueField.addEventListener('input', check);
kindField.value = 'iban';
valueField.value = 'AE07 0331 2345 6789 0123 456';
check();
#verdict { font-weight: 600; }
#verdict[data-state='valid'] { color: #16a34a; }
#verdict[data-state='invalid'] { color: #dc2626; }
#verdict[data-state='structure'] { color: #d97706; }
#detail { min-height: 92px; }