IdentifierField
One field for an email address or a phone number, which tells them apart as they're typed and formats a phone number as it goes.
import { IdentifierField } from "@butteryui/react";Demo
When to use it
Use it for
- The first step of a passwordless sign-in or sign-up, as AuthFlow draws it
- Anywhere either an email address or a phone number will do, such as where to send a receipt
Not for
- Only an email address: use TextField with type email
- A whole sign-in screen: use AuthFlow
Examples
Gift note
Both looks: the outlined field for who's buying, and a soft one for who the bag is a gift for.
Left unfinished
Nothing's said while it's typed; leave it unfinished and it says what it needs.
Receipt form
Where a café sends a receipt: an email or a phone, with a box to keep it for next time.
Remembered
A field the app fills with the email it remembers, and empties when someone wants another.
Signing in as rosa@halfmoon.coffee.
Send a code
An email or a phone number, formatted as it's typed, with a button that waits until it's whole.
We'll send a code to sign you in.
Variants and states
As it's typed
A phone number formatted as it goes, an email address left as written, and one that couldn't be used.
Too many codes sent. Try again in a minute.
Props
IdentifierField
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | "Email or phone number" | What the field asks for. Defaults to "Email or phone number". |
value | string | The text, a phone number as formatted. Pair with onValueChange to control it. | |
defaultValue | string | The starting text when uncontrolled. | |
onValueChange | ((value: string) => void) | Called with the text on every change, a phone number formatted as it's shown. | |
passkey | boolean | false | Offers saved passkeys too, with autocomplete="username webauthn". Defaults to false. |
error | ReactNode | What's wrong, from outside the field, such as a code that couldn't be sent. Shown in place of its own message. | |
invalidMessage | string | What it says once it's left with something that isn't an email address or a phone number. | |
hint | ReactNode | A hint under the label, such as the format expected. | |
variant | "outline" | "soft" | "outline" | "outline" (the default), a 1px control-border edge on bg-surface, or "soft", a bg-control fill whose
edge shows only on hover and while it has focus, for a field on a card or in a toolbar. |
iconStart | ComponentType<IconComponentProps> | An icon at the start of the box, such as Mail from lucide-react. Decorative. | |
iconEnd | ComponentType<IconComponentProps> | An icon at the end of the box. Decorative. | |
announceError | boolean | true | Whether a new error is read out as it appears. Defaults to true; turn it off when an error summary
that takes focus reads the errors instead. |
It also takes Omit<ComponentPropsWithRef<"input">, "size" | "value" | "defaultValue" | "children" | "type" | "inputMode" | "autoComplete">.
Accessibility
A labelled text input ("Email or phone number" by default). It asks for the keyboard and the autofill that match what's typed: email, tel, or username until it can tell, and "username webauthn" with passkey to offer saved passkeys. It says nothing while it's typed in; once it's left with something that can't be used, the error describes it and is read out with the field's name.
| Keys | What they do |
|---|---|
| Letters, numbers and symbols | Type them in, a phone number formatted as it goes |
| Enter | Submits the form it's in |
Motion
It doesn't move.
With reduced motion: Nothing changes.
Layout
It fills its container's width at --bt-h-cta (48px) with 16px text, so phones don't zoom in. The error sits under the box and wraps.