PhoneNumberField
PhoneNumberField lar brukeren oppgi et telefonnummer med landkode. Komponenten setter sammen en søkbar landvelger (der brukeren velger land, ikke skriver tallkode) og et nummerfelt som formateres mens brukeren skriver, under én felles label. De to er uavhengige felt: hver kan ha sin egen feilmelding, og i React bindes de som to separate React Hook Form-felt.
PhoneNumberField reimplementerer ingenting selv: den grupperer en Combobox (landkode) og et TextField med formatering (nummer). All filtrering, virtual focus, formatering og form-synk kommer uendret fra de to.
Egnet til
- Skjemaer der brukeren skal oppgi telefonnummer med landkode
- Tjenester som møter kunder fra flere land (velg land fremfor å kunne tallkoden)
- Situasjoner der landkode-feltet ikke bør se like «tungt» ut som nummeret
Uegnet til
- Rene norske nummer der landkode er unødvendig (bruk et vanlig TextField med
format="phone") - Fri tekst / nummer som ikke skal valideres som telefon
Bruk
Landvelgeren bruker den innebygde landlista (Norge øverst, så Norden, så alfabetisk). Skriv i nummerfeltet: det formateres til 123 45 678 mens du skriver, men onChange og form-innsending gir alltid den rå verdien uten mellomrom.
Eksempler
Med beskrivelse
To felt i React Hook Form
Komponenten er to uavhengige felt: landkode og nummer. I React binder du dem med hver sin registrering, countryField og numberField, som spres rett på delfeltene. Begge indre komponenter (Combobox og TextField) er register-kompatible, så {...register()} fungerer uten lim-kode:
countryField={register('landkode')}:onChangefår landkoden (uten+) ievent.target.value.numberField={register('tlf')}:onChangefår den rå nummer-verdien (uten separatorer) ievent.target.value.
Feilmeldinger er per felt: errorMessage vises under nummeret, countryErrorMessage under landvelgeren. defaultCountryCode gir et forhåndsvalgt land når registreringen ikke selv seeder verdien.
function Skjema() {
const { register, handleSubmit, formState: { errors } } = useForm();
return (
<Form onSubmit={handleSubmit(console.log)} noValidate>
<PhoneNumberField
label="Mobilnummer"
description="Norsk format: 123 45 678"
countryLabel="Landkode"
numberLabel="Telefonnummer"
noHitsText="Ingen treff"
toggleLabel="Vis landkoder"
countryField={register('landkode', { required: 'Velg landkode' })}
numberField={register('tlf', { pattern: { value: /^\d{8}$/, message: 'Åtte siffer' } })}
errorMessage={errors.tlf?.message}
countryErrorMessage={errors.landkode?.message}
/>
</Form>
);
}
Å bytte land reformaterer ikke nummeret. Formatet er uavhengig av valgt land. For kontrollert bruk uten RHF: bind hvert delfelt manuelt via numberField/countryField ({ name, onChange, onBlur, ref }), eller bruk <Controller>.
Egen landliste
Utelates countries fyller web-komponenten inn den innebygde standardlista i språket fra locale (nb | nn | en). Send inn din egen countries for å begrense eller utvide: samme form som Combobox-options (value = landkode, label = kallekode +kode (vises som valgt verdi), description = landnavn). I ren HTML tilsvarer dette data-countries med en JSON-array av samme form.
Engelsk landliste
Med feilmelding
Feilene er uavhengige: errorMessage vises under nummeret, countryErrorMessage under landvelgeren. Utelat den ene for å vise feil kun på det andre feltet.
Deaktivert
disabled propageres til både landvelgeren og nummerfeltet.
Retningslinjer
La brukeren velge land, ikke skrive tallkode
Ingen skal måtte huske at Sverige er +46. I lista står kallekoden som primærtekst med
landnavnet under, og brukeren kan søke på begge. Da blir verdien i det smale landfeltet
kort og entydig (+47), mens landnavnet er der som kontekst i lista.
Ikke bruk emoji-flagg
Windows viser dem som «NO» og «SE», skjermlesere leser dem ulikt, og i liten størrelse er Norge og Island samme flagg. Komponenten er derfor laget uten flagg: kallekode og landnavn som tekst oppfører seg likt i alle tjenester.
Gjør nummerfeltet bredere enn landvelgeren
Er de to feltene like brede, ser de ut som to like felt, og brukeren begynner å skrive nummeret i det første. Bredden er det som viser hvilket felt som er hovedfeltet.
Send eget format for andre land enn Norge
Standarden er norsk 8-sifret (123 45 678) uansett hvilket land som er valgt. Andre
nummerlengder krever at du sender inn numberFormat/numberFormatPattern. Formateringen er
bare visuell: verdien som sendes, er alltid rå og uten mellomrom.
Universell utforming
Gruppe med felles navn
<ix-phone-number-field> setter role="group" og kobler den felles labelen (data-field="legend") via aria-labelledby. Skjermlesere annonserer de to feltene som én gruppe med et felles navn. De to kontrollene beholder sin egen rolle, navn og verdi. Combobox følger ARIA APG combobox-mønsteret, nummerfeltet er en native input.
Feltets formål eksponeres (1.3.5)
Web-komponenten stamper nummerfeltet med type="tel", inputmode="numeric" og autocomplete="tel-national" (når de mangler) slik at mobilt tastatur viser tall, og nettleser/hjelpemidler kan autofylle telefonnummer.
Feilmelding per felt annonseres
Hvert felt eier sin egen feilmelding. I React setter errorMessage feil på nummerfeltet og countryErrorMessage på landvelgeren. Hvert indre ix-field/ix-combobox kobler meldingen via aria-describedby, setter aria-invalid="true" på sin egen input, og annonserer polite via aria-live (avbryter ikke brukeren). I ren HTML kan du fortsatt legge en felles gruppe-feil i [data-field="error"] direkte på host.
Fokusrekkefølge og tastatur
Tab flytter fokus fra landvelger til nummerfelt (samme som leserekkefølgen). Landvelgeren er fullt tastaturopererbar (piltast/Enter/Escape), nummerfeltet er et vanlig tekstfelt.
Send inn oversatt tekst (i18n)
label, countryLabel, numberLabel, noHitsText (påkrevd), toggleLabel og resultsText må sendes inn på riktig språk (bokmål, nynorsk, engelsk). Det finnes ingen fallback. Den innebygde landlista lokaliseres med locale (data-locale i ren HTML), men er også fullt overstyrbar via countries (data-countries).
Tastaturnavigasjon
| Tast | Handling |
|---|---|
| Tab | Flytter fokus til landvelgeren, deretter til nummerfeltet |
| Pil ned / Pil opp | Åpner og navigerer i landlista når landvelgeren har fokus |
| Enter | Velger markert land i landlista |
| Escape | Lukker landlista uten å endre valg |
| Skriving | I landvelgeren filtrerer teksten lista; i nummerfeltet skrives telefonnummeret (formateres til 123 45 678) |
Skjermleser
- Ved fokus inn i komponenten: "[label], gruppe" — leses opp som group med legend som navn
- Ved fokus på landvelgeren: "[countryLabel], combobox" med APG-annonsering av alternativer og antall treff
- Hvert alternativ leses i DOM-rekkefølge: kallekoden først, så landnavnet (f.eks. «+47, Norge»). Valgt verdi som vises i landfeltet er kallekoden.
- Ved fokus på nummerfeltet: "[numberLabel], redigering, tekst"
- Ved feiltilstand: aria-invalid annonseres som «ugyldig» på gruppa, og feilmeldingsteksten leses opp polite via aria-live
- Når description er satt: leses opp som del av gruppe-konteksten via aria-describedby
WCAG-kriterier
Sist gjennomgått: 2026-07-15 — alle 56 WCAG 2.2-kriterier vurdert
WCAG-kriterier9 ditt ansvar · 17 håndtert · 37 ikke relevant · 0 ikke på plass
Ditt ansvar (9)
| Kriterium | Nivå | Hva du må gjøre |
|---|---|---|
| 1.3.1 Informasjon og relasjoner | A | Skriv beskrivende felles label. label er gruppens tilgjengelige navn (leses som legend av skjermlesere). "Mobilnummer" er bedre enn "Nummer". Den beskriver hva de to feltene til sammen samler inn — ikke handlingen. |
| 2.4.6 Overskrifter og ledetekster | AA | Skriv beskrivende felles label. label er gruppens tilgjengelige navn (leses som legend av skjermlesere). "Mobilnummer" er bedre enn "Nummer". Den beskriver hva de to feltene til sammen samler inn — ikke handlingen. |
| 3.3.2 Ledetekster eller instruksjoner | A | Skriv beskrivende felles label. label er gruppens tilgjengelige navn (leses som legend av skjermlesere). "Mobilnummer" er bedre enn "Nummer". Den beskriver hva de to feltene til sammen samler inn — ikke handlingen. |
| 3.3.2 Ledetekster eller instruksjoner | A | Gi begge feltene et tilgjengelig navn. countryLabel og numberLabel er påkrevde aria-label på henholdsvis landvelgeren og nummerfeltet. Feltene har ingen egen synlig label — gruppens legend navngir helheten, mens aria-label skiller de to. "Landkode" og "Telefonnummer" på riktig språk. |
| 4.1.2 Navn, rolle, verdi | A | Gi begge feltene et tilgjengelig navn. countryLabel og numberLabel er påkrevde aria-label på henholdsvis landvelgeren og nummerfeltet. Feltene har ingen egen synlig label — gruppens legend navngir helheten, mens aria-label skiller de to. "Landkode" og "Telefonnummer" på riktig språk. |
| 3.3.1 Identifikasjon av feil | A | Skriv konkret feilmelding. errorMessage skal forklare hva brukeren må gjøre. "Skriv inn et gyldig telefonnummer" er bedre enn "Ugyldig". Komponenten viser meldingen på gruppenivå, setter aria-invalid på host og annonserer den polite — men teksten er ditt ansvar. |
| 3.3.3 Forslag ved feil | AA | Skriv konkret feilmelding. errorMessage skal forklare hva brukeren må gjøre. "Skriv inn et gyldig telefonnummer" er bedre enn "Ugyldig". Komponenten viser meldingen på gruppenivå, setter aria-invalid på host og annonserer den polite — men teksten er ditt ansvar. |
| 3.1.2 Språk på deler av innhold | AA | Send inn combobox-tekstene på riktig språk. noHitsText (påkrevd), toggleLabel og resultsText videreføres til landvelgeren og må oversettes (bokmål, nynorsk, engelsk). Den innebygde landlista lokaliseres med locale, men UI-chrome har ingen fallback. |
| 3.3.2 Ledetekster eller instruksjoner | A | Vurder bruk av disabled. Et deaktivert felt er vanskelig å forstå uten forklaring, og disabled bryter kontrastkravet (1.4.3 unntar disabled-elementer). Vurder om feltet heller bør forklares eller skjules. |
Håndtert av komponenten (17)
| Kriterium | Nivå | Hva komponenten gjør |
|---|---|---|
| 1.3.1 Informasjon og relasjoner | A | ix-phone-number-field setter role="group", aria-labelledby til den felles legend, og aria-describedby til description og error. De to kontrollene (ix-combobox og nummer-input) beholder sin egen ARIA. |
| 1.3.5 Identifiser formål med inndata | AA | Nummerfeltet får autocomplete="tel-national", type="tel" og inputmode="numeric" slik at feltets formål eksponeres programmatisk og nettleser/hjelpemidler kan autofylle telefonnummer. |
| 1.4.1 Bruk av farge | A | Valgt land vises som tekst — kallekoden (f.eks. +47) i landfeltet, med landnavnet som sekundær tekst i lista. Valgt-tilstand i lista markeres med checkmark (form) — ikke kun farge. Feiltilstand vises både med aria-invalid, tekstmelding og farge. |
| 1.4.3 Kontrast (minimum) | AA | Tekst bruker --ix-color-foreground-main-default mot standard bakgrunn. Forventes å oppfylle 4,5:1. Verifiser ved egendefinerte bakgrunnsfarger. |
| 1.4.10 Omflyt | AA | Reflower korrekt ned til 320 px: den smale landvelgeren (kun kallekode) og nummerfeltet ligger side ved side på én rad hele veien; nummerfeltet krymper (min-width: 0) i stedet for å tvinge horisontal scroll. |
| 1.4.11 Kontrast for ikke-tekstlig innhold | AA | Feltenes border og fokus-indikatorer arves fra combobox.css og text-field.css (--ix-color-border-main-default / --ix-color-fill-*). Forventes å oppfylle 3:1. |
| 1.4.12 Tekstavstand | AA | Bruker relative enheter og tåler økt line-height, bokstav- og ordavstand uten tap av innhold. |
| 2.1.1 Tastatur | A | Fullt tastaturopererbar: Tab når landvelger så nummerfelt, combobox har eget APG-tastaturmønster (piltast/Enter/Escape), nummerfeltet er en vanlig tekst-input. |
| 2.4.3 Fokusrekkefølge | A | Fokusrekkefølge følger DOM: landvelger før nummerfelt, som samsvarer med leserekkefølgen. |
| 2.4.7 Synlig fokus | AA | :focus-visible på begge feltene gir tydelig outline (arvet fra underliggende komponenter). |
| 2.5.5 2.5.5 | ? | Toggle-knapp, alternativer og inputfelter oppfyller minimum 44×44 px klikkflate (arvet fra combobox/text-field). |
| 2.5.8 Målstørrelse (minimum) | AA | Klikkeflaten på 44×44 px oppfyller WCAG 2.2 AA-kravet (24×24 px) med god margin. |
| 3.3.1 Identifikasjon av feil | A | ix-phone-number-field setter aria-invalid="true" på host når errorMessage har innhold, og kobler feilmeldingen via aria-describedby. |
| 3.3.2 Ledetekster eller instruksjoner | A | Felles legend + per-felt aria-label gir instruksjoner/etiketter for begge kontrollene. |
| 3.3.3 Forslag ved feil | AA | errorMessage brukes til å gi konkret feilmelding. Komponenten viser den, men teksten er konsumentens ansvar. |
| 4.1.2 Navn, rolle, verdi | A | role="group" med aria-labelledby gir gruppa navn og rolle. De to kontrollene eksponerer egne roller/navn/verdier (combobox-mønster og native input). |
| 4.1.3 Statusmeldinger | AA | ix-phone-number-field setter aria-live="polite" på error-elementet slik at endringer i feilmeldingen annonseres uten å avbryte brukeren. |
Ikke relevant (37)
| Kriterium | Nivå | Hvorfor ikke relevant |
|---|---|---|
| 1.1.1 Ikke-tekstlig innhold | A | |
| 1.2.1 Bare lyd og bare video (forhåndsinnspilt) | A | Ingen medieelementer. |
| 1.2.2 Teksting (forhåndsinnspilt) | A | Ingen medieelementer. |
| 1.2.3 Synstolking eller mediealternativ (forhåndsinnspilt) | A | Ingen medieelementer. |
| 1.2.4 Teksting (direkte) | AA | Ingen medieelementer. |
| 1.2.5 Synstolking (forhåndsinnspilt) | AA | Ingen medieelementer. |
| 1.3.3 Sensoriske egenskaper | A | |
| 1.3.4 Visningsretning | AA | Ingen fast orientering — tilpasser seg visningsretning. |
| 1.4.2 Styring av lyd | A | Ingen lydelementer. |
| 1.4.4 Endre tekststørrelse | AA | |
| 1.4.5 Bilder av tekst | AA | Ingen bilder av tekst. |
| 1.4.13 Innhold ved hover eller fokus | AA | |
| 2.1.2 Ingen tastaturfelle | A | |
| 2.1.4 Tastatursnarveier | A | Ingen egendefinerte tastatursnarveier. |
| 2.2.1 Justerbar hastighet | A | Ingen tidsbegrensede funksjoner. |
| 2.2.2 Pause, stopp, skjul | A | Ingen animasjon eller automatisk oppdatering. |
| 2.3.1 Terskelverdi på tre glimt | A | Ingen blinkende eller glimtende innhold. |
| 2.4.1 Hoppe over blokker | A | Sidekrav — gjelder ikke enkeltkomponenter. |
| 2.4.2 Sidetitler | A | Sidekrav — gjelder ikke enkeltkomponenter. |
| 2.4.4 Formål med lenke (i kontekst) | A | Ingen lenker i komponenten. |
| 2.4.5 Flere måter | AA | Sidekrav — gjelder ikke enkeltkomponenter. |
| 2.4.11 Fokus ikke skjult (minimum) | AA | Ingen sticky/overlappende elementer som kan skjule fokus. |
| 2.5.1 Pekerbevegelser | A | Ingen drag-and-drop eller sveipebevegelser. |
| 2.5.2 Avbryt peker | A | |
| 2.5.4 Bevegelsesaktivering | A | Ingen bevegelsesbasert interaksjon. |
| 2.5.6 Samtidige inndatamekanismer | A | |
| 2.5.7 Drabevegelser | A | Ingen drag-and-drop. |
| 3.1.1 Språk på siden | A | Sidekrav — gjelder ikke enkeltkomponenter. |
| 3.1.2 Språk på deler av innhold | AA | Alt innhold er på gruppens språk; komponenten setter ikke lang på deler. |
| 3.2.1 Ved fokus | A | |
| 3.2.2 Ved inndata | A | |
| 3.2.3 Konsistent navigasjon | AA | Sidekrav — gjelder ikke enkeltkomponenter. |
| 3.2.4 Konsistent identifikasjon | AA | Systemkrav — gjelder konsistens på tvers av sider, ikke enkeltkomponenter. |
| 3.2.6 Konsistent hjelp | A | Sidekrav — gjelder plassering av hjelpefunksjon på tvers av sider. |
| 3.3.4 Forhindring av feil (juridisk, økonomisk, data) | AA | Flytkrav — gjelder bekreftelse/reversering av transaksjoner, ikke enkeltfelter. |
| 3.3.7 Redundant oppføring | A | Flytkrav — gjelder at brukeren ikke skal gjenta informasjon i en prosess. |
| 3.3.8 Tilgjengelig autentisering (minimum) | AA | Ikke en autentiseringskomponent. |
Props / API
PhoneNumberFieldProps
| Prop | Type | Påkrevd | Standard | Beskrivelse |
|---|---|---|---|---|
label | string | Ja | Synlig felles label over begge feltene (legend) | |
countryLabel | string | Ja | aria-label på landvelgeren (i18n) | |
numberLabel | string | Ja | aria-label på nummerfeltet (i18n) | |
noHitsText | string | Ja | Tekst i landlista ved 0 treff (i18n) | |
description | string | Nei | Felles hjelpetekst under label | |
errorMessage | string | Nei | Feilmelding for nummer-feltet. Setter aria-invalid på nummer-inputen når den har innhold | |
countryErrorMessage | string | Nei | Feilmelding for landkode-feltet. Uavhengig av errorMessage | |
placeholder | string | Nei | Frarådes — placeholder er et a11y-antimønster. Bruk description for hjelpetekst/format-hint i stedet | |
toggleLabel | string | Nei | aria-label på landvelgerens chevron-knapp (i18n) | |
resultsText | string | Nei | Mal for annonsering av antall treff i landlista, {n} = antall (i18n) | |
countryField | FieldRegistration | Nei | RHF-registrering for landkode: register('landkode'). { name, onChange, onBlur, ref } — spres på landvelgeren | |
defaultCountryCode | string | Nei | Forhåndsvalgt landkode (uten +) når countryField ikke eier verdien | |
numberField | FieldRegistration | Nei | RHF-registrering for nummer: register('tlf'). { name, onChange, onBlur, ref } — spres på nummerfeltet | |
defaultValue | string | Nei | Ukontrollert start-nummer (rå verdi) når numberField ikke eier verdien | |
countries | CountryOption[] | Nei | innebygd liste | Overstyr landlista |
locale | 'nb' | 'nn' | 'en' | Nei | 'nb' | Språk for den innebygde standardlista |
numberFormat | string | FieldFormatter | Nei | 'phone' | Format for nummeret (norsk 8-sifret som standard) |
numberFormatPattern | string | Nei | Pattern-streng (0 = siffer). Alternativ til numberFormat | |
numberFormatLive | boolean | Nei | Overstyr formatterens live-modus | |
disabled | boolean | Nei | Deaktiverer begge feltene | |
readOnly | boolean | Nei | Skrivebeskytter begge feltene | |
required | boolean | Nei | Markerer både landvelger og nummerfelt som påkrevd | |
className | string | Nei | CSS-klasse på <ix-phone-number-field> | |
id | string | Nei | id på gruppen | |
ref | Ref<IxPhoneNumberField> | Nei | Ref videresendes til <ix-phone-number-field> |
FieldRegistration
Struktur-typen countryField/numberField tar. Matcher det React Hook Form register() returnerer, men er en ren struktur-type. Pakka har ingen RHF-avhengighet, så egne handlers eller en <Controller>-kobling fungerer også.
| Felt | Type | Beskrivelse |
|---|---|---|
name | string | Feltnavn ved form-innsending |
onChange | (event) => unknown | Får et event der verdien ligger i event.target.value |
onBlur | (event) => unknown | Touched-state / mode: 'onBlur' |
ref | Ref | Videresendes til delfeltets host (landvelger / nummer-proxy) |
CountryOption
Samme form som ComboboxOption. Utelates countries fyller web-komponenten inn sin innebygde standardliste (lokalisert med locale).
| Felt | Type | Beskrivelse |
|---|---|---|
value | string | Landkoden uten + (verdien landvelgeren sender) |
label | string | Kallekoden, f.eks. +47 — vist som valgt verdi (primærtekst) |
description | string | Landnavnet (sekundær tekst i lista) |
Tilpasning med CSS
| Element | Selektor |
|---|---|
| Rot | .ix-phone-number-field (eller ix-phone-number-field) |
| Felt-wrapper | [data-field="items"] |
| Landvelger-kolonne | [data-field="country"] |
| Nummer-kolonne | [data-field="number"] |
Relatert
- Combobox — landvelgeren som gjenbrukes
- TextField og formatering — nummerfeltet og
format="phone" - ValidationMessage — feilmeldingens markup