Theme studio

Design a theme, preview it live, then export it. Saved in this browser.

Quick picks #10b981
Generated scale
50100200300400500600700800900
Some text is below AA

InputPhone

  • Needs review
  • WCAG 2.2 evidence
  • RTL
  • Web · iOS · Android

Phone number field: a label, a field box with a country picker (flag, dial code, chevron) and a number input, helper text and an inline error. Built on React Aria TextField (the number: type="tel", inputMode="tel", autoComplete="tel-national") and Select (the country: a button with a listbox popup), reusing the Input field parts and the Select list and options, so it looks and behaves like both. Accessibility: the label, helper and error are linked to the number (WCAG 1.3.1, 3.3.2); the box is a group named by the label; the country button is named by countryLabel, the country name and the dial code ("Country Pakistan +92"), so the country is always available as text even when only a flag is visible (1.1.1). Tab moves from the country button to the number; Enter, Space, Arrow Down or Arrow Up open the list, typing a letter picks a country by name, Escape closes and returns focus (2.1.1, 2.4.3). With isRequired / validate / native constraints the error appears on submit, focus moves to the number and the error is read with it; it shows an icon and text, never colour alone (1.4.1, 3.3.1, 4.1.3). Paste and autofill are never blocked; a pasted international number selects its country (3.3.7, 3.3.8). The dial code and the number form one phone number that reads left to right, so the box never mirrors in right-to-left layouts (rule G4); the label, helper, error and the list do. Consumer duties: the country list (names translated, dial codes correct), label, helper and error wording, validation rules per country, the autoComplete token (1.3.5) and why a field is disabled.

import { InputPhone } from "@nexera-ui/react";
Loading example…
10
examples
42
props
10
live controls
3
platforms
18
WCAG criteria
3
blocks use it

Try every prop. Copy the code.

Change the props and the code updates. Check light and dark, LTR and RTL, and phone width.

Loading…
defaultOpen
description
placeholder
digits
inputMode
platform
isDisabled
isReadOnly
isRequired
isInvalid
Generated code
import { InputPhone } from "@nexera-ui/react";

<InputPhone />

Examples 9

The same examples as Storybook, rendered live. Open Code to copy one.

States

Semantic states: filled, isDisabled, isInvalid + errorMessage and read-only.

Loading example…

Country list open

The country list is open: flag, name and dial code per country; the selected one has a check mark.

Loading example…

Validation on submit

Validation on submit: the error appears under the field with an icon, focus moves to the number and the error is read with it. validate receives the national number with Latin digits. Paste is never blocked: pasting "+971 50 123 4567" selects the United Arab Emirates and keeps "50 123 4567".

Loading example…

Platforms

Input Mobile pattern on iOS (50 pt) and Android (52 dp): radius 12, Body/Large, 20 px chevron. Web is 40 px.

Loading example…

Without flags

Flags are optional: the button then shows the dial code, and the list shows names and dial codes.

Loading example…

Long label

Long labels and helper texts wrap; the number scrolls inside the box.

Loading example…

Right to left

Right-to-left: the label, helper text and country list mirror; the dial code and the number form one phone number that reads left to right, so the field box keeps its order.

Loading example…

Locale digits

digits="locale": under an ar-EG locale the number and dial codes use Arabic-Indic digits. The value, validate and the submitted form value keep Latin digits. Without it the field shows Latin digits in every locale.

Loading example…

Contact verification

Loading example…

Props 42

Press "Try it" on a card to load that prop into the playground.

42 props shown

countries*Nexera
readonly InputPhoneCountry[]

The countries to pick from (consumer data: the library ships no country list and no flag assets). Each entry has a unique code, a translated name, a dialCode and an optional decorative flag. Put the most likely countries first or pass defaultCountry. Figma Country flag and Dial code are taken from the selected entry.

Default –
countryNexera
string

Code of the selected country (controlled). Pair it with onCountryChange.

Default –
defaultCountryNexera
string

Code of the country selected on first render (uncontrolled).

Default the first entry of `countries`
onCountryChangeNexera
(code: string) => void

Called with the new country code when the user picks a country, or when a pasted international number selects one.

Default –
countryLabelNexera
string

First part of the country button's accessible name, followed by the country name and dial code ("Country Pakistan +92"); also the name of the country list. Translate it for your locale.

Default Country
countryFieldNameNexera
string

Form field name under which the selected country code is submitted (the number uses name).

Default –
isOpenNexera
boolean

Whether the country list is open (controlled). Use with onOpenChange.

Default –
defaultOpenNexera
boolean

Whether the country list is open on first render (uncontrolled).

Default false
onOpenChangeNexera
(isOpen: boolean) => void

Called when the country list opens or closes.

Default –
valueNexera
string

The national number, without the dial code, always with Latin digits. Pair it with onChange.

Default –
defaultValueNexera
string

The national number on first render (uncontrolled).

Default –
onChangeNexera
(value: string) => void

Called with the national number as the user edits it. Digits typed in another numbering system (٣٠٠, ۳۰۰,...) arrive as Latin digits. Pasting or autofilling an international number (+92 300 1234567) selects the country whose dial code starts it and keeps only the national part.

Default –
descriptionNexera
ReactNode

Helper text under the field, for example the expected format. Linked to the number with aria-describedby. Replaced by the error message while the field is invalid, as in the Figma Error state.

Default –
errorMessageNexera
ReactNode | ((validation: ValidationResult) => ReactNode)

Error text under the field, shown with an icon while the field is invalid (isInvalid, or a failed isRequired / validate / native constraint after submit) and linked with aria-describedby. Say what is wrong and how to fix it ("Enter a valid mobile number for Pakistan"). A function receives React Aria's validation result.

Default –
placeholderNexera
string

Example number shown while the field is empty. Never the only label.

Default –
digitsNexera
"latin" | "locale"

Digits shown in the number and the dial codes: "latin" (0-9) whatever the locale, or "locale" for the numbering system of the I18nProvider / NexeraProvider locale (for example ٠-٩ for ar-EG). The value, onChange, validate and the submitted form value always use Latin digits.

Default latin
autoCompleteNexera
string

Autofill token of the number (WCAG 1.3.5). The country is picked separately, so the default asks for the national number; use "tel" to let the browser fill the full international number (its dial code then selects the country).

Default tel-national
inputModeNexera
"none" | "text" | "tel" | "url" | "email" | "numeric" | "decimal" | "search"

Virtual keyboard of the number.

Default tel
platformNexera
"web" | "ios" | "android"

Platform look: 50 pt / 52 dp box with Body/Large text on iOS and Android. Defaults to the NexeraProvider platform.

Default "web"
inputRefNexera
Ref<HTMLInputElement>

Ref to the native number <input> (the root ref points to the field wrapper).

Default –
classNameNexera
string

Extra classes for the root, merged last so they win over the defaults.

Default –
styleNexera
CSSProperties

Inline style of the root.

Default –
labelNexera
FieldLabelContent

Visible label, linked to the control by React Aria (WCAG 1.3.1, 3.3.2). Short noun, for example "Work email". Wraps instead of truncating. A placeholder is never a substitute for it. Not set: the field has no visible label. Not set: the field has no visible label of its own.

Default –
aria-labelNexera
string

Accessible name when it must differ from the visible label. Prefer the visible label (WCAG 2.5.3). Accessible name. Required when there is no visible label; translate it. Accessible name. Optional when aria-labelledby is set.

Default –
aria-labelledbyNexera
string

Id(s) of element(s) that name the field; wins over the visible label. Id(s) of element(s) that name the field; wins over aria-label. Id(s) of visible element(s) that name the field.

Default –
validationBehaviorReact Aria
"native" | "aria"

Whether to use native HTML form validation to prevent form submission when the value is missing or invalid, or mark the field as required or invalid via ARIA.

Default 'native'
enterKeyHintReact Aria
"search" | "enter" | "done" | "go" | "next" | "previous" | "send"

An enumerated attribute that defines what action label or icon to preset for the enter key on virtual keyboards. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/enterkeyhint).

Default –
isDisabledReact Aria
boolean

Whether the input is disabled.

Default –
isReadOnlyReact Aria
boolean

Whether the input can be selected but not changed by the user.

Default –
isRequiredReact Aria
boolean

Whether user input is required on the input before form submission.

Default –
isInvalidReact Aria
boolean

Whether the value is invalid.

Default –
validateReact Aria
(value: string) => true | ValidationError | null

A function that returns an error message if a given value is invalid. Validation errors are displayed to the user when the form is submitted if validationBehavior="native". For realtime validation, use the isInvalid prop instead.

Default –
autoFocusReact Aria
boolean

Whether the element should receive focus on render.

Default –
aria-describedbyReact Aria
string

Identifies the element (or elements) that describes the object.

Default –
idReact Aria
string

The element's unique identifier. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id).

Default –
maxLengthReact Aria
number

The maximum number of characters supported by the input. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefmaxlength).

Default –
minLengthReact Aria
number

The minimum number of characters required by the input. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefminlength).

Default –
patternReact Aria
string

Regex pattern that the value of the input must match to be valid. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefpattern).

Default –
autoCorrectReact Aria
string

An attribute that takes as its value a space-separated string that describes what, if any, type of autocomplete functionality the input should provide. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#autocomplete).

Default –
spellCheckReact Aria
string

An enumerated attribute that defines whether the element may be checked for spelling errors. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/spellcheck).

Default –
nameReact Aria
string

The name of the input element, used when submitting an HTML form. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefname).

Default –
formReact Aria
string

The <form> element to associate the input with. The value of this attribute must be the id of a <form> in the same document. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input#form).

Default –

* Required. React Aria props shown are the ones most apps use; the component accepts the rest of its React Aria props too.

Accessible by default.

Built on React Aria, and covered by the WCAG 2.2 evidence generated on every build.

WCAG 2.2 evidence

12 direct · 6 supporting
  • 1.1.1Non-text ContentLevel A · tested directly
  • 1.3.1Info and RelationshipsLevel A · tested directly
  • 1.3.2Meaningful SequenceLevel A · supporting test
  • 1.3.5Identify Input PurposeLevel AA · tested directly
  • 1.4.1Use of ColorLevel A · tested directly
  • 1.4.10ReflowLevel AA · supporting test
  • 1.4.11Non-text ContrastLevel AA · supporting test
  • 1.4.12Text SpacingLevel AA · supporting test
  • 2.1.1KeyboardLevel A · tested directly
  • 2.4.3Focus OrderLevel A · tested directly
  • 2.4.7Focus VisibleLevel AA · supporting test
  • 2.5.8Target Size (Minimum)Level AA · supporting test
  • 3.3.1Error IdentificationLevel A · tested directly
  • 3.3.2Labels or InstructionsLevel A · tested directly
  • 3.3.3Error SuggestionLevel AA · tested directly
  • 3.3.7Redundant EntryLevel A · tested directly
  • 3.3.8Accessible Authentication (Minimum)Level AA · tested directly
  • 4.1.2Name, Role, ValueLevel A · tested directly

Fits any width.

Nexera components respond to the space they are given. Drag the corner of the frame, or pick a width.

0 px · drag the corner

Styling hooks

Pass className to add Tailwind classes (merged last). State is exposed as data attributes, so you can style it with variants like data-pressed:.

  • data-disabled
  • data-focus-within
  • data-hovered
  • data-invalid
  • data-open
  • data-pressed
Usage
<InputPhone className="data-disabled:opacity-90 shadow-sm" />

Used in blocks

Related components