MaskField
A value typed into a shape — a date, a time, a card number, or a pattern of your own.
Overview
A value typed into a shape — a date, a time, a card number, or a pattern of your own.
First example
<MaskField mask="credit-card" onValueChange={setCard}><MaskField.Label>Card number</MaskField.Label><MaskField.Field /></MaskField><MaskFieldmask="date"locale="fr-FR"convert={text => parseMaskedDate(text, 'fr-FR')}onValueChange={(text, value) => setBirthday(value as Date | null)}><MaskField.Label>Date de naissance</MaskField.Label><MaskField.Field /><MaskField.Description>Jour, mois, année.</MaskField.Description></MaskField>
Anatomy
<MaskField>
<MaskField.Field />
</MaskField>
Usage
<MaskField mask="credit-card" onValueChange={setCard}>
<MaskField.Label>Card number</MaskField.Label>
<MaskField.Field />
</MaskField>
<MaskField
mask="date"
locale="fr-FR"
convert={text => parseMaskedDate(text, 'fr-FR')}
onValueChange={(text, value) => setBirthday(value as Date | null)}
>
<MaskField.Label>Date de naissance</MaskField.Label>
<MaskField.Field />
<MaskField.Description>Jour, mois, année.</MaskField.Description>
</MaskField>
Root props
MaskFieldProps
The node's inherited React Native props apply too, and so do its style props — padding, margin, width and the rest.
| Prop | Type | Required | Description |
|---|---|---|---|
| mask | MaskSpec | Yes | The shape the box is masked to. Required — there is no default shape. |
| value | string | undefined | No | The masked text. Present means controlled — the field follows it, and `onValueChange` is how it asks for a new one. `''` is an empty field. |
| defaultValue | string | undefined | No | Where an uncontrolled field starts. Masked on the way in, so a raw string is fine. |
| onValueChange | ((text: string, value: unknown) => void) | undefined | No | Every edit: the masked text, and — when `convert` is set — what it converts to, or `null` while the text is not a value yet. Without `convert` the second argument is the masked text itself. |
| convert | ((text: string) => unknown) | undefined | No | Turns the masked text into a value of your own — a `Date`, `{ hours, minutes }`, a card number. Return `null` while the text is not one yet. The field stays about the string; this is the one plug. `parseMaskedDate` and `parseMaskedTime` are exported for the `date` and `time` shapes. |
| order | DateOrder | undefined | No | Which date part is typed first, for the `date` and `datetime` shapes. Unset, it is read out of `locale`. Give it when the order is a decision — an ISO field is `YMD`. |
| locale | string | undefined | No | The order and the separator come from here when neither is given. |
| separator | string | undefined | No | Between the date parts. Unset, it is the one the locale writes. |
| segmentLabels | SegmentLabels | undefined | No | What the placeholder calls each date part — `{ day: 'JJ', month: 'MM', year: 'AAAA' }`. The letters are a language's, so the default is the `DD` / `MM` / `YYYY` code is written in. A `placeholder` on the field wins over it. |
| children | ReactNode | No | — |
Slots
MaskFieldFieldProps
The node's inherited React Native props apply too, and so do its style props — padding, margin, width and the rest.
Variants, sizes and colour
Accessibility
Migration from legacy
Implementation notes
It is a `TextField`
The root below is the TextField's root, unchanged: the same recipe, the same four
variants, the same size, radius, color, labelPlacement, isInvalid and
isDisabled. MaskField.Label, .Description and .Error are the TextField's slots
— the same components, re-exported rather than wrapped — and only MaskField.Field differs,
by masking what is typed into it. The TextArea's arrangement exactly, and TextField is
not touched.
It is a mask, not a set of segments
There is one representation — the accepted characters, in order — and maskInput is the
only thing that turns them into text. Everything else is dropped, including the literals,
which are put back rather than kept.
That is what makes the field survive a paste, a keyboard that offers its own punctuation, and a backspace over a separator, none of which a segmented field survives without a rule each.
`mask` is a preset or a pattern
| preset | shape | rules |
|---|---|---|
'date' | DD/MM/YYYY | order and separator from locale; each part clamped, never raised |
'time' | HH:MM | 24-hour; hour ≤ 23, minute ≤ 59 |
'datetime' | DD/MM/YYYY HH:MM | the two above, joined by a space |
'credit-card' | #### #### #### #### | shape only |
MASK_FIELD_MASKS is the list of them.
Anything else is a pattern string:
| token | accepts |
|---|---|
# | a digit |
A | a letter |
* | either |
| other | a literal, put back in as the parts fill |
<MaskField mask="+33 # ## ## ## ##" />
<MaskField mask="AA## ####" />
A pattern is a shape, not a range — it does not clamp. If a custom mask needs clamping, that
is a follow-up, an object form { pattern, clamp }.
The date parts come from the locale
Read out of Intl rather than off a table of countries. order overrides it when the
order is a decision rather than a locale — an ISO field is YMD wherever it is read.
separator and segmentLabels ({ day, month, year }) override the rest.
A date that cannot exist — the 31st of February — is capped by the mask the moment the
month is known, and parseMaskedDate returns null for one typed before it, rather than
rolling forward into March the way new Date would.
The value is the masked string
value / defaultValue / onValueChange operate on the masked text, controlled or not, as
everywhere in the library. A raw string handed to value is masked on the way in.
convert is the one plug that turns the text into a value of your own:
<MaskField mask="time" convert={parseMaskedTime} onValueChange={(text, time) => …} />
parseMaskedDate(text, locale?, order?) → Date | null and parseMaskedTime(text) →
{ hours, minutes } | null are exported for the date and time shapes, with
formatMaskedDate / formatMaskedTime as their inverses. Without convert,
onValueChange's second argument is the masked text itself.
For a date chosen rather than typed
That is DatePicker — a trigger, an overlay and a Calendar in it. MaskField is the box
alone; it has no picker.