InputsReact
A text input that formats what is typed to a fixed pattern: a phone number, a card number, an expiry date, a code.
Rendered by React 19.3.1
Loading React…Installation
npm i @hamur/reactNot on npm yet. The package goes out under the chosen name.
Anatomy
Import the component and assemble its parts:
<MaskedInput.Root>
<MaskedInput.Input />
<MaskedInput.Guide />
</MaskedInput.Root>Examples
Card
A card number whose mask function groups 15 digits for 34 and 37, checked by Field's validate.
Expiry
An expiry date 99/99 with one message for an incomplete date and one for a month over 12.
Code
A gift card code whose tokens upper-case letters, typed over with overwrite.
Format On Blur
A phone number with formatOnBlur: raw digits while focused, formatted once the field is left.
Controlled
The raw value held by the app, set and cleared from outside, its formatted text from MaskedInput.format.
Form
A required phone number in a form, with a message for a missing and an incomplete value, and a reset.
API reference
23 props across 3 parts, in React syntax. className, style, render are listed once, under Shared props.
GuideMaskedInput.Guide
A template of the mask drawn behind or over the input: the typed text, kept invisible so it only takes its width, then the rest of the template with each empty slot drawn as placeholderChar. Hidden from assistive technology. Renders a <span>.
InputMaskedInput.Input
The text input whose text follows the mask. It is the field's labelled control; its value is the Root's. Renders an <input>.
| Prop | Type | Default |
|---|---|---|
typeThe input's type. | MaskedInputType | 'text' |
inputModeThe virtual keyboard to show. | "search" | "text" | "none" | "tel" | "url" | "email" | "numeric" | "decimal" | — |
autoCapitalizeThe autocapitalize hint for virtual keyboards. | string | — |
autoCorrectThe autocorrect hint for virtual keyboards. | string | 'off' |
spellCheckWhether the browser checks the spelling of the value. | Booleanish | false |
RootMaskedInput.Root
Groups the masked input and its guide, holds the raw value, and renders the hidden input the form submits. Renders a <div>.
| Prop | Type | Default |
|---|---|---|
maskrequiredThe mask: a string where 9 is a digit, a a letter, * either and \ makes the next | MaskedInputMaskProp | — |
tokensSlot characters to add or redefine, merged over 9, a and *. | MaskedInputTokens | — |
valueThe raw value, without literals. | string | — |
defaultValueThe raw value when the component is initially rendered, and the value a form reset restores. | string | '' |
onValueChangeCallback fired when the raw value changes. | ((value: string, eventDetails: MaskedInputRootChangeEventDetails) => void) | — |
onValueCompleteCallback fired after onValueChange when an edit fills the last slot, or when a paste gives | ((value: string, eventDetails: MaskedInputRootCompleteEventDetails) => void) | — |
onValueInvalidCallback fired when typed, pasted or dropped text has characters the mask rejects. | ((value: string, eventDetails: MaskedInputRootInvalidEventDetails) => void) | — |
normalizeValueNormalizes every incoming text before it is conformed to the mask: typed, pasted and dropped | ((text: string) => string) | — |
overwriteWhether typing replaces the slot character at the caret instead of inserting before it. | boolean | false |
formatOnBlurWhether the input shows the raw value while focused and the formatted text otherwise. | boolean | false |
placeholderCharThe character the guide draws in each empty slot. | string | '_' |
formValueWhat the form submits: the raw value or the formatted text. | MaskedInputFormValue | 'raw' |
nameIdentifies the field when a form is submitted. | string | — |
formThe id of the form element the hidden input belongs to. | string | — |
requiredWhether the user must enter a value before submitting a form. | boolean | false |
disabledWhether the component should ignore user interaction. | boolean | false |
readOnlyWhether the user should be unable to change the value. | boolean | false |
inputRefA ref to the hidden input that holds the form value. | React.Ref<HTMLInputElement> | — |
Shared props
Every part that renders an element takes these.
| Prop | Type |
|---|---|
classNameCSS class applied to the element, or a function that
returns a class based on the component's state. | string | ((state: State) => string | undefined) |
styleStyle applied to the element, or a function that
returns a style object based on the component's state. | React.CSSProperties | ((state: State) => React.CSSProperties | undefined) |
renderAllows you to replace the component's HTML element
with a different tag, or compose it with another component. | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, State> |
Keyboard and accessibility
Keyboard
| Keys | Does | Part |
|---|---|---|
| Fill the next slot, with the literals before it | Input | |
| A character the slot does not take changes nothing | Input | |
| Backspace | Deletes the slot character before the caret, past the literals, and shifts the rest | Input |
| Delete | Deletes the slot character after the caret, past the literals | Input |
| ControlZMetaZ | Undoes the last edit; Meta+Z on Apple platforms | Input |
| ControlShiftZControlY | Redoes the edit undone last | Input |
Accessibility
| Part | Sets | So that |
|---|---|---|
| Input | a plain input with no role, no placeholder and no aria-placeholder; value is the formatted text | it is read as the text field it is, with the text the user sees |
| Input | aria-labelledby the Field label, aria-describedby its description and errors, aria-invalid, aria-required | the name, the format, the error and the rule are said with the field |
| Input | inputmode from the mask (numeric for digits only), autocapitalize characters for upper-cased letters, autocorrect off, spellcheck false | the phone keyboard fits the slots, and nothing rewrites the text by itself |
| Guide | aria-hidden="true", no role | the slots still to fill are seen but never read |
| Root | the hidden input with tabindex="-1", aria-hidden="true", name, required and the mask's pattern | the form value and its validity never add a stop or a name |
Focus order
- The Input is one tab stop; the Guide and the hidden input are never focused.
- Focus by Tab, by the label or by the app keeps the selection the browser puts there; nothing takes focus on mount or on a form reset.