Skip to content

PhoneField

A country dialling code and a phone number under one label, with the tel keyboard and autocomplete.

  • Pro
  • Version 2.0.0-rc.1
  • APG pattern: Group: select-only combobox and tel input

Examples

Still previews of the real component, rendered from its stories. Pro code isn’t public, so nothing in them responds. Switch the theme and density for every preview at once.

Default

Phone numberWe only call about your order.
Country code
Show the code

Default, code

<PhoneField hint="We only call about your order." />

With a value

Phone number
Country code
Show the code

With a value, code

<PhoneField defaultValue={{ country: 'IE', number: '87 123 4567' }} />

Invalid

Phone number
Country code
Error: Enter a phone number, like 07700 900 982
Show the code

Invalid, code

<PhoneField
  isInvalid
  errorMessage="Enter a phone number, like 07700 900 982"
  defaultValue={{ country: 'GB', number: '0770' }}
/>

Tokens

The 4 design tokens PhoneField reads, with the value each has in the theme and density chosen above. Change a token and the component follows, in Figma and in code.

Show all 4 tokens
Tokens PhoneField reads
TokenValue nowCSS variable
color.text.secondary…--sd-color-text-secondary
field.label…--sd-field-label
spacing.gap.sm…--sd-spacing-gap-sm
spacing.stack.xs…--sd-spacing-stack-xs

Install

Pro components come as source from the SuperDuper registry, with a licence key from Solo, Team or Studio. The registry and checkout aren’t open yet.

Add it from the registry (Pro licence key)

npx shadcn@latest add @superduperui/phone-field

Then import it

import { PhoneField, defaultPhoneCountries } from "@/components/ui/phone-field"

Props

PhoneField props
PropTypeWhat it does
labelstringDefault 'Phone number'Group label. Default "Phone number".
hintstring
errorMessagestring
isInvalidboolean
isRequiredboolean
isDisabledboolean
countriesPhoneCountry[]Default [ { code: 'GB', name: 'United Kingdom', dial: '44' }, { code: 'IE', name: 'Ireland', dial: '353' }, { code: 'FR', name: 'France', dial: '33' }, { code: 'DE', name: 'Germany', dial: '49' }, { code: 'ES', name: 'Spain', dial: '34' }, { code: 'US', name: 'United States', dial: '1' }, { code: 'AU', name: 'Australia', dial: '61' }, ]
valuePhoneValue
defaultValuePhoneValue
onChange(value: PhoneValue) => void
namestringForm field names (number and country).
classNamestring

When to use it

Use it for

  • Phone numbers that may be international
  • Delivery and account contact details

Use something else for

  • UK-only numbers: use TextField type tel

Accessibility

Screen readers announce "Phone number, group" then "Country code, United Kingdom +44, button" and "Number, edit text".

WCAG 2.2 AAA criteria the component meets in Comfortable density: 1.4.6, 1.4.9, 2.1.3, 2.3.2, 2.4.13, 2.5.5, 2.5.6.

Compact density meets AA (2.5.8, 24px targets), not AAA.

What your product still has to do

  • Accept spaces and brackets in numbers; normalise on the server

Shared patterns it ships with: 1.3.6 (tel-national autocomplete, inputmode tel).

This release’s test results

Test results for PhoneField in this release
axe-core (WCAG A, AA, AAA and best practice)80 runs across every story, theme, density and width: 0 violations
Rendered text contrast115 text runs: 0 below 7:1, lowest 8.43:1
Target size32 targets: 0 under 44px in Comfortable
Focus appearance (2.4.13)36 focus stops in 3 browser engines: all pass
Keyboard scriptChromium 5 of 5, Firefox 5 of 5, WebKit 5 of 5

Manual passes with VoiceOver and NVDA haven’t been done yet.

Keyboard

Each step is scripted and run in Chromium, Firefox and WebKit.

PhoneField keyboard steps
KeyWhat happens
TabTab reaches the country code select
EnterEnter opens the list of countries
ArrowDownDown moves to the next country
EnterEnter picks it and returns to the select
TabTab moves to the number input

In Figma

The Figma component is PhoneField, with State (Default, Hover, Focus, Disabled, Invalid). The Figma library isn’t published yet.

Figma to code: State (Default, Hover, Focus, Disabled = isDisabled, Invalid = isInvalid); Country → defaultValue.country (hidden mirror of the nested Select, read as a fallback; shown as name +dial code); Number → defaultValue.number (hidden mirror of the nested TextField, read as a fallback); Label → label; Hint → hint when Show hint; nested Select → defaultValue.country (the Select Value, as an ISO code from the country list); nested TextField → defaultValue.number|isInvalid|errorMessage|isDisabled (the TextField Value, its State Invalid or Disabled and its FieldError message).