Code
Code captures a short, fixed-length verification code.
Components · Form
A code field captures a short, fixed-length value — a one-time password, a PIN, a signing confirmation code. Namirial doesn't give it dedicated tokens; it's a composition of single-character input cells laid out in a row, so it inherits sizes, focus, and validation for free.
Overview
The Code Field component is designed for entering short verification codes, where each character is entered into its own input cell. This layout improves readability, makes input errors easier to spot, and supports common authentication and verification flows.
When to use
Use the Code Field component when:
- Users need to enter a one-time password (OTP) received via SMS, email, or an authenticator app.
- Users need to enter or confirm a short PIN or verification code.
- A workflow requires a short confirmation or signing code as part of a secure process.
Anatomy
Each cell is a full .nm-input instance — container and field — with maxlength="1" and centered text, laid out with a simple flex row. There is no .nm-code class in the theme; the row is just display: flex with a gap.
Tokens and values that drive each part
| Part | Role | Source |
|---|---|---|
| Cell | Every visual property | --nm-input-* — identical to a size-matched input (see Input) |
| Cell width | Fixed so digits don't reflow | 32px, same at every size |
| Cell | Border radius, both sizes | 8px |
| Row | Gap between cells | 8px |
| Text | Centered in the cell | text-align: center on .nm-input__field |
Sizes
Code only supports two sizes — sm and lg — pick lg for signing flows where legibility at a glance matters most.
States
Each cell carries its own focus ring, so the currently-active cell is unambiguous. Validation is applied to the whole row at once, not per cell.
Focus state
First digit entered, second cell focused and awaiting input
Error — all four cells recolor together with nm-input--error, with a status icon alongside the row
Error states
All code cells recolor together with nm-input--error.
Error message - placed directly beneath the row, exactly like a standard input fields.
Help text + error — If persistent help text (e.g. a countdown) is shown, keep it in its neutral color and display the error on a second line below it. This keeps the countdown visible during validation.
Success state
Success — shown once the whole code validates.
Behavior
A code field needs a small amount of JavaScript beyond CSS: typing a digit should auto-advance focus to the next cell, Backspace on an empty cell should move focus back, and pasting a full code should split it across every cell.
const cells = Array.from(row.querySelectorAll('.nm-input__field'));
cells.forEach((cell, i) => {
cell.addEventListener('input', () => {
cell.value = cell.value.replace(/\D/g, '').slice(0, 1);
if (cell.value && cells[i + 1]) cells[i + 1].focus();
});
cell.addEventListener('keydown', (e) => {
if (e.key === 'Backspace' && !cell.value && cells[i - 1]) cells[i - 1].focus();
});
cell.addEventListener('paste', (e) => {
const digits = e.clipboardData.getData('text').replace(/\D/g, '').split('');
if (digits.length < 2) return;
e.preventDefault();
digits.slice(0, cells.length).forEach((d, j) => { cells[j].value = d; });
cells[Math.min(digits.length, cells.length) - 1].focus();
});
});Validate and submit only once every cell is filled — don't ask the user to press a separate "Verify" button for a 4–6 digit code if you can submit automatically on completion.
Light & dark theme
Do & don't
Accessibility
Semantics
- Use
<input inputmode="numeric" pattern="[0-9]*" maxlength="1">per cell so mobile keyboards default to a numeric pad. - Wrap the row in a
<fieldset>with a<legend>describing what the code is for ("Verification code sent to your phone").
Keyboard
- Auto-advance and auto-retreat (described in Behavior) must not trap focus — Tab and Shift+Tab should still move a keyboard user through cells normally if they choose not to type sequentially.
- Paste-splitting must not break the browser's native paste handling for users who paste one cell at a time.
Labeling
- Announce validation results in an
aria-live="polite"region near the field — don't rely on color or shake animation alone. - Give the fieldset an
aria-describedbypointing at any help or countdown text ("Code expires in 4:59").
Playground
Type digits, paste a full code, or use Backspace to move back.
Implementation
<link rel="stylesheet" href="namirial-theme.css">
<fieldset>
<legend>Verification code</legend>
<div class="code-field">
<div class="nm-input nm-input--lg">
<div class="nm-input__container">
<input class="nm-input__field" inputmode="numeric" pattern="[0-9]*" maxlength="1" placeholder="-">
</div>
</div>
<!-- repeat per digit -->
</div>
</fieldset>CSS classes
| Class | Values | Default |
|---|---|---|
nm-input--{size} | sm · lg per cell — the only two sizes code supports | lg |
nm-input--{intent} | error · success, applied to every cell (or the last, for success) | — |
code-field | Flex row with an 8px gap and fixed cell width | — |