MaskedInput
A controlled text input that enforces a character-by-character mask pattern. Supports digits, letters, alphanumeric slots, and arbitrary literal separators with full keyboard navigation.
Mask Syntax
Build a mask string using the reserved characters below. Any other character is treated as a fixed literal separator.
| Character | Accepts | Example slot |
|---|---|---|
| 9 | Digit (0–9) | 5 |
| a | Letter (a–z, A–Z) | B |
| * | Alphanumeric (a–z, A–Z, 0–9) | X3 |
| other | Fixed literal separator | -, /, (, ) … |
Phone Number
Mask (999) 999-9999 — digits only with formatted separators.
US Phone Number
import { MaskedInput } from 'fluxo-ui';
const [phone, setPhone] = useState('');
<MaskedInput
mask="(999) 999-9999"
value={phone}
onChange={(e) => setPhone(e.value)}
/>Date
Mask 99/99/9999 — calendar date with slash separators.
Date (MM/DD/YYYY)
<MaskedInput
mask="99/99/9999"
value={date}
onChange={(e) => setDate(e.value)}
/>Time
Mask 99:99 — 24-hour or 12-hour time input.
Time (HH:MM)
<MaskedInput
mask="99:99"
value={time}
onChange={(e) => setTime(e.value)}
/>Social Security Number
Mask 999-99-9999 — SSN with dash separators.
SSN
<MaskedInput
mask="999-99-9999"
value={ssn}
onChange={(e) => setSsn(e.value)}
/>Credit Card
Mask 9999 9999 9999 9999 — four groups of four digits separated by spaces.
Credit Card Number
<MaskedInput
mask="9999 9999 9999 9999"
value={cc}
onChange={(e) => setCc(e.value)}
/>IPv4 Address
Mask 999.999.999.999 — four octet groups with dot separators.
IPv4 Address
<MaskedInput
mask="999.999.999.999"
value={ip}
onChange={(e) => setIp(e.value)}
/>Alphanumeric — License Plate
Mask aaa-9999 — three letters, a dash, then four digits.
Vehicle License Plate
<MaskedInput
mask="aaa-9999"
value={plate}
onChange={(e) => setPlate(e.value)}
/>Raw Value vs Masked Value
Use includeLiterals=false to receive only the typed digits/letters in onChange, without the separator characters.
includeLiterals comparison
onChange emits e.g. (123) 456-7890
onChange emits e.g. 1234567890
<MaskedInput
mask="(999) 999-9999"
includeLiterals={false}
value={phone}
onChange={(e) => setPhone(e.value)}
onRawChange={(raw, masked) => console.log(raw, masked)}
/>Pre-filled Value
Pass a value prop at mount time (raw or masked) and the component normalises it into the mask.
Pre-filled inputs
<MaskedInput mask="(999) 999-9999" value="5551234567" onChange={(e) => setPhone(e.value)} />
<MaskedInput mask="99/99/9999" value="01/15/1990" onChange={(e) => setDate(e.value)} />
<MaskedInput mask="9999 9999 9999 9999" value="4111111111111111" onChange={(e) => setCc(e.value)} />States
Disabled and Read-only
<MaskedInput mask="(999) 999-9999" value={v} onChange={(e) => setV(e.value)} />
<MaskedInput mask="(999) 999-9999" value={v} onChange={(e) => setV(e.value)} disabled />
<MaskedInput mask="(999) 999-9999" value={v} onChange={(e) => setV(e.value)} readonly />
<MaskedInput mask="(999) 999-9999" value={v} onChange={(e) => setV(e.value)} required />Custom Slot Character
Use slotChar to change the placeholder shown for empty editable slots (default is _).
Custom slotChar
<MaskedInput mask="(999) 999-9999" slotChar="#" value={v} onChange={(e) => setV(e.value)} />
<MaskedInput mask="99/99/9999" slotChar="·" value={v} onChange={(e) => setV(e.value)} />Keyboard Navigation
| Key | Behaviour |
|---|---|
| Any valid char | Insert into the current editable slot and advance cursor |
| Backspace | Clear the slot to the left of the cursor |
| Delete | Clear the slot under the cursor |
| ← / → | Jump to previous / next editable slot |
| Home | Jump to the first editable slot |
| End | Jump to the slot after the last filled character |
| Tab | Default browser tab-focus behaviour (not intercepted) |
| Paste | Insert pasted text character-by-character, skipping non-matching chars |
Import
import { MaskedInput } from 'fluxo-ui';Props
maskstringMask pattern. Use '9' for digit, 'a' for letter, '*' for alphanumeric, any other char as literal separator. Either mask or preset must be provided
maskstringMask pattern. Use '9' for digit, 'a' for letter, '*' for alphanumeric, any other char as literal separator. Either mask or preset must be provided
preset'phone' | 'phone-us' | 'phone-intl' | 'date' | 'date-us' | 'ssn' | 'credit-card' | 'zip' | 'zip-plus4' | 'time'Built-in mask preset that auto-fills the mask and a SR-readable format hint
preset'phone' | 'phone-us' | 'phone-intl' | 'date' | 'date-us' | 'ssn' | 'credit-card' | 'zip' | 'zip-plus4' | 'time'Built-in mask preset that auto-fills the mask and a SR-readable format hint
formatHintstringFormat hint string surfaced under the input and linked via aria-describedby. Auto-derived from preset when not provided
formatHintstringFormat hint string surfaced under the input and linked via aria-describedby. Auto-derived from preset when not provided
valuestringCurrent value (raw or masked — component normalises it)
valuestringCurrent value (raw or masked — component normalises it)
onChange(event: ComponentEvent<string>) => voidCalled when the value changes
onChange(event: ComponentEvent<string>) => voidCalled when the value changes
onRawChange(raw: string, masked: string) => voidCalled with the raw (unmasked) value alongside the masked display value
onRawChange(raw: string, masked: string) => voidCalled with the raw (unmasked) value alongside the masked display value
slotCharstring"_"Character shown for empty mask slots
slotCharstring"_"Character shown for empty mask slots
includeLiteralsbooleantrueWhether to include literal separator characters in the onChange value
includeLiteralsbooleantrueWhether to include literal separator characters in the onChange value
errorstring | booleanError message string (also marks invalid). Pass `true` to mark invalid without a visible message
errorstring | booleanError message string (also marks invalid). Pass `true` to mark invalid without a visible message
invalidbooleanForce the field into an invalid state without an error message
invalidbooleanForce the field into an invalid state without an error message
helperTextReactNodeHelper text rendered under the input and linked via aria-describedby
helperTextReactNodeHelper text rendered under the input and linked via aria-describedby
placeholderstringPlaceholder text. Defaults to the mask itself
placeholderstringPlaceholder text. Defaults to the mask itself
requiredbooleanfalseMark the input as required
requiredbooleanfalseMark the input as required
readonlybooleanfalseMake the input read-only
readonlybooleanfalseMake the input read-only
disabledbooleanfalseDisable the input
disabledbooleanfalseDisable the input
autoFocusbooleanfalseAuto-focus on mount
autoFocusbooleanfalseAuto-focus on mount
idstringUnique id for the input element
idstringUnique id for the input element
Features
Flexible Mask Syntax
Use '9' for digits, 'a' for letters, '*' for alphanumeric, and any other char as a fixed separator
Raw Value Access
onRawChange gives you the unformatted value alongside the masked display string
Pre-filled Values
Pass a raw or masked value at mount time and the component normalises it automatically
Custom Slot Character
Replace the default underscore placeholder for empty slots with any character
Keyboard Navigation
Arrow keys, Home, End, Backspace, Delete, and paste all work with slot-aware behaviour
includeLiterals Control
Choose whether onChange emits separators (e.g. dashes, spaces) or raw characters only
Accessibility
Keyboard-only operable, ARIA attributes, and screen-reader-friendly slot announcements
Theming
Full dark/light + 5 brand themes via CSS variables — zero extra config