Masked Input
Preview: Phone
Text field that formats input against a pattern as you type. `onValueChange` gives both masked and raw values.
Import
import { MaskInput } from '@marbleui/ui'Props
<MaskInput>
| Prop | Type | Default | Description |
|---|---|---|---|
| mask *required | 'card' | 'us-phone' | 'intl-phone' | 'expiry' | 'date' | 'postal' | 'iban' | (string & {}) | — | |
| description | ReactNode | — | |
| errorMessage | string | ((validation: ValidationResult) => string) | — | |
| label | ReactNode | — | |
| onValueChange | (masked: string, raw: string) => void | — | |
| placeholder | string | — | |
| prefix | ReactNode | — | Decorations inside the field, before / after the text. |
| suffix | ReactNode | — | |
| variant | FieldVariant | — |
Also accepts React Aria props (119).
Usage notes
Text field that formats as you type, for card numbers, phone numbers, expiry dates and IBANs. For quantities use NumberField; for one-time codes use OTPField.
<MaskInput label="Card number" mask="card" onValueChange={(masked, raw) => setCardNumber(raw)} />
<MaskInput label="Order reference" mask="aa-9999" />
- Presets:
card,us-phone,intl-phone,expiry,date,postal(9999 aa) andiban. Any other string is a custom pattern:9a digit,aa letter (uppercased),*either; other characters are inserted for you. - The value lives inside the component: there’s no
value;defaultValueprefills it (masked on the way in). Read it throughonValueChange(masked, raw);rawdrops the separators. - The placeholder defaults to the pattern (
0000 0000 …), and digit-only patterns setinputMode="numeric"for a number keypad on touch devices. - A half-filled value still passes
isRequired; check completeness withvalidate.
Example source · show· hide
import { useState } from 'react'
import { MaskInput } from './mask-input'
function Phone() {
const [raw, setRaw] = useState('')
return <div className="flex w-64 flex-col gap-2"><MaskInput label="Phone" mask="us-phone" onValueChange={(_, r) => setRaw(r)} /><span className="text-xs text-fg-muted">Raw: {raw || '—'}</span></div>
}
export const styles = {
Phone,
Presets: () => <div className="grid w-[30rem] grid-cols-2 gap-3"><MaskInput label="Card number" mask="card" /><MaskInput label="Expiry" mask="expiry" /><MaskInput label="Date" mask="date" /><MaskInput label="Postal code (NL)" mask="postal" /><MaskInput label="IBAN" mask="iban" className="col-span-2" /></div>,
}Source: packages/ui/src/mask-input/mask-input.tsx
Catalog
- Category
- inputs
- Priority
- Extra
- Primitive
- custom
- React Aria
- TextField
- Base UI
- Input