Combobox
Combobox lar brukeren søke etter og velge ett eller flere alternativer fra en liste. Brukeren skriver for å filtrere, og valgte alternativer vises enten som verdi i feltet (single) eller som chips over feltet (flervalg).
Combobox er en sammensatt komponent med en del markup. Combobox i ren HTML gir en full gjennomgang av anatomien, hvordan et valg fungerer, forhåndsvalg og form-innsending.
Egnet til
- Lange lister der brukeren raskt vil filtrere seg frem
- Valg der søk er raskere enn å skanne alle alternativer (f.eks. land, kommune)
- Flervalg der valgte alternativer bør vises tydelig som chips
- Situasjoner der brukeren kjenner navnet på det de leter etter
Uegnet til
- Korte lister med få alternativer (bruk RadioGroup eller Select)
- Når brukeren skal skrive inn en fri verdi som ikke finnes i lista
- Når alle alternativer alltid bør være synlige samtidig
Kom i gang
Kode
<Combobox label="Land" placeholder="Søk etter land …" noHitsText="Ingen treff" toggleLabel="Vis alternativer" options={[ { value: '47', label: 'Norge', description: '+47' }, { value: '46', label: 'Sverige', description: '+46' }, { value: '45', label: 'Danmark', description: '+45' }, { value: '358', label: 'Finland', description: '+358' }, ]} />
Prøv å skrive for å filtrere lista. Søket treffer både label, verdi og beskrivelse — så «+47» eller «47» finner Norge like godt som «Norge». Filtreringen er locale-bevisst (norsk collator, æ/ø/å-korrekt og aksent-uavhengig). noHitsText og toggleLabel er tekster du selv oversetter.
Eksempler
Forhåndsvalgte verdier
I React setter du startverdi med defaultValue (ukontrollert) eller value (kontrollert). I ren HTML markerer du alternativet med aria-selected="true" — se Combobox i ren HTML for detaljene.
Kode
<Combobox label="Land" placeholder="Søk etter land …" noHitsText="Ingen treff" toggleLabel="Vis alternativer" defaultValue="47" options={[ { value: '47', label: 'Norge', description: '+47' }, { value: '46', label: 'Sverige', description: '+46' }, { value: '45', label: 'Danmark', description: '+45' }, ]} />
I React setter du startverdi med defaultValue (ukontrollert) eller value (kontrollert) — '47' i single, ['47', '46'] i flervalg.
Kontrollert vs. ukontrollert (React)
I React kan feltet være ukontrollert eller kontrollert:
- Ukontrollert: sett
defaultValuefor startverdi. Komponenten eier verdien etter mount, og senere endringer avdefaultValueignoreres (som i vanlige React-inputs). - Kontrollert: sett
valueog oppdater den ionChange. Da er React sanningskilden.
Verditypen følger multiple: string i single, string[] i flervalg. I single får onChange en tom streng ('') når alt fjernes. onChange kalles ved valg, avmarkering og fjerning av chip.
Kode
function KontrollertLand() { const [land, setLand] = React.useState('47'); return ( <> <Combobox label="Land" noHitsText="Ingen treff" toggleLabel="Vis alternativer" value={land} onChange={setLand} options={[ { value: '47', label: 'Norge' }, { value: '46', label: 'Sverige' }, { value: '45', label: 'Danmark' }, ]} /> <p>Valgt verdi: {land || '(ingen)'}</p> </> ); }
Søk/filtrering skjer inne i web-komponenten (locale-bevisst, treffer label, verdi og beskrivelse) og kan ikke overstyres med en prop fra React. Ved 0 treff vises noHitsText i en role="status"-region.
Flervalg med chips
I flervalg holdes lista åpen etter valg, inputfeltet tømmes, og valgte alternativer vises som chips. Chips nås med piltast og fjernes med Backspace eller klikk.
Kode
<Combobox label="Land" multiple placeholder="Søk etter land …" noHitsText="Ingen treff" toggleLabel="Vis alternativer" removeChipLabel="fjern" arrowHintText="Bruk piltastene for å navigere mellom valgte alternativer" defaultValue={['47', '46']} options={[ { value: '47', label: 'Norge', description: '+47' }, { value: '46', label: 'Sverige', description: '+46' }, { value: '45', label: 'Danmark', description: '+45' }, { value: '358', label: 'Finland', description: '+358' }, ]} />
Med hjelpetekst
Kode
<Combobox label="Land" description="Søk og velg landet du bor i" placeholder="Søk …" noHitsText="Ingen treff" toggleLabel="Vis alternativer" options={[ { value: '47', label: 'Norge' }, { value: '46', label: 'Sverige' }, { value: '45', label: 'Danmark' }, ]} />
Med feilmelding
Kode
<Combobox label="Land" errorMessage="Du må velge et land for å fortsette" placeholder="Søk …" noHitsText="Ingen treff" toggleLabel="Vis alternativer" options={[ { value: '47', label: 'Norge' }, { value: '46', label: 'Sverige' }, ]} />
Deaktivert
Kode
<Combobox label="Land" disabled defaultValue="47" noHitsText="Ingen treff" toggleLabel="Vis alternativer" options={[ { value: '47', label: 'Norge' }, { value: '46', label: 'Sverige' }, ]} />
Retningslinjer
Tydelige labels gir forutsigbarhet
Alle combobox-felter skal ha en synlig og beskrivende label. Labelen skal beskrive hvilken informasjon feltet gjelder, ikke handlingen. Skriv "Land" i stedet for "Søk og velg land".
Bruk combobox når søk er raskere enn å skanne
Combobox egner seg når listen er lang eller vanskelig å skanne. For korte lister gir radio-knapper eller Select bedre oversikt.
Valgt verdi må alltid være tydelig
I single vises valgt verdi i feltet. I flervalg vises hvert valg som en chip over feltet. I begge moduser får valgte alternativer en checkmark i lista (struktur, ikke farge alene). Brukeren skal aldri være i tvil om hva som er valgt.
"Kun velg fra liste"
Komponenten lar brukeren velge blant eksisterende alternativer — ikke skrive inn frie verdier. Trenger du fri tekst, bruk et vanlig tekstfelt.
Sorter alternativene forutsigbart
Alternativene bør sorteres alfabetisk, eller med de mest relevante øverst i lange lister, slik at brukeren raskt finner frem.
Tilgjengelighet / universell utforming
Semantisk struktur og korrekt rolle
Combobox følger ARIA Authoring Practices sitt combobox-mønster: inputfeltet får role="combobox" med aria-autocomplete="list", aria-expanded og aria-controls. Lista er role="listbox" og alternativene role="option". I single settes aria-selected="true" kun på det valgte alternativet (de øvrige har ingen aria-selected, så skjermleseren slipper å lese «ikke valgt» for hvert). I flervalg vises valgte verdier som chips med role="button" i en role="group"-wrapper (chipsLabel) — ikke som option-er utenfor en listbox.
Virtual focus
DOM-fokus blir alltid på inputfeltet. Aktivt alternativ spores med aria-activedescendant, slik at brukeren kan skrive og pil-navigere samtidig uten at fokus flyttes fysisk inn i lista.
Tydelig fokus og tastaturnavigasjon
Combobox er fullt opererbar med tastatur. Feltet nås med Tab, lista åpnes ved skriving eller piltast, alternativer velges med Enter og lista lukkes med Escape. I flervalg nås chips med piltast og fjernes med Backspace.
Tilstrekkelig størrelse og klikkeflate
Toggle-knappen og alternativene oppfyller minimum 44×44 px klikkflate.
i18n — send inn oversatt tekst
Komponenten har ingen innebygde tekster. noHitsText, toggleLabel, removeChipLabel, chipsLabel, arrowHintText og resultsText må sendes inn på riktig språk (bokmål, nynorsk, engelsk). Det finnes ingen norsk fallback — det ville smittet over på andre språk.
I utviklingsbygg (import.meta.env.DEV) varsler web-komponenten med console.warn når en påkrevd tekst mangler: toggle-knappen uten aria-label (React: toggleLabel), flervalg uten data-remove-chip-label (React: removeChipLabel) eller uten data-chips-label (React: chipsLabel), eller input uten tilgjengelig navn. resultsText er en forbedring — mangler den, annonseres antall treff ikke (ingen advarsel). Advarslene fjernes fra produksjonsbygg.
Tastaturnavigasjon
| Tast | Handling |
|---|---|
| Tab | Flytter fokus til inputfeltet |
| Shift+Tab | Flytter fokus til forrige fokuserbare element |
| Bokstav | Filtrerer lista og åpner den |
| Arrow Down | Åpner lista / flytter aktivt alternativ nedover |
| Arrow Up | Flytter aktivt alternativ oppover |
| Enter | Velger aktivt alternativ (lukker lista i single, holder åpen i multi) |
| Escape | Lukker lista uten å endre valg |
| Backspace | Tom input i multi: flytter fokus til siste chip. På chip: fjerner chipen |
| Arrow Left/Right | Flervalg: navigerer mellom valgte chips |
Skjermleser
- Ved fokus: "[label], kombinasjonsboks, sammenrullet"
- Ved skriving: aktivt alternativ annonseres via aria-activedescendant: "[alternativ], [posisjon] av [total]" (single leser "valgt" kun på det valgte, ikke "ikke valgt" på hvert)
- Ved filtrering: antall treff annonseres via en skjult role=status (resultsText), f.eks. "5 alternativer"
- Flervalg: "[label], kombinasjonsboks" + skjult aria-describedby-hint som forklarer chip-navigasjon
- Ved 0 treff: no-hits-teksten annonseres via role=status
- Valgt chip: "[alternativ], [fjern-tekst], knapp" i gruppen [chipsLabel]
- Ved feil: "[label], ugyldig, kombinasjonsboks, [feilmelding]"
WCAG-kriterier
Sist gjennomgått: 2026-07-13 — alle 56 WCAG 2.2-kriterier vurdert
WCAG-kriterier8 ditt ansvar · 18 håndtert · 30 ikke relevant · 0 ikke på plass
Ditt ansvar (8)
| Kriterium | Nivå | Hva du må gjøre |
|---|---|---|
| 2.4.6 Overskrifter og ledetekster | AA | Skriv beskrivende labeltekst. Labelen skal forklare hva brukeren skal velge — ikke handlingen. "Land" er bedre enn "Søk og velg land". Alle combobox-felter må ha en label, enten synlig eller via ariaLabel. |
| 3.3.2 Ledetekster eller instruksjoner | A | Skriv beskrivende labeltekst. Labelen skal forklare hva brukeren skal velge — ikke handlingen. "Land" er bedre enn "Søk og velg land". Alle combobox-felter må ha en label, enten synlig eller via ariaLabel. |
| 3.1.1 Språk på siden | A | Send inn oversatt tekst for alle strenger. noHitsText, toggleLabel, removeChipLabel, chipsLabel, arrowHintText og resultsText leses av skjermleser og/eller vises i UI. Komponenten har ingen innebygde fallback-tekster — send inn riktig streng for språket ditt (bokmål, nynorsk, engelsk). resultsText er en mal med {n} som byttes med antall treff. |
| 3.1.2 Språk på deler av innhold | AA | Send inn oversatt tekst for alle strenger. noHitsText, toggleLabel, removeChipLabel, chipsLabel, arrowHintText og resultsText leses av skjermleser og/eller vises i UI. Komponenten har ingen innebygde fallback-tekster — send inn riktig streng for språket ditt (bokmål, nynorsk, engelsk). resultsText er en mal med {n} som byttes med antall treff. |
| 3.3.1 Identifikasjon av feil | A | Skriv gode feilmeldinger. Feilmeldingen må si hva som er galt og hva brukeren skal gjøre. "Du må velge et land" — ikke "Ugyldig valg". Komponenten viser og annonserer meldingen, men du skriver innholdet. |
| 3.3.3 Forslag ved feil | AA | Skriv gode feilmeldinger. Feilmeldingen må si hva som er galt og hva brukeren skal gjøre. "Du må velge et land" — ikke "Ugyldig valg". Komponenten viser og annonserer meldingen, men du skriver innholdet. |
| 2.4.6 Overskrifter og ledetekster | AA | Bruk meningsfulle option-tekster. Hvert alternativ skal ha en tydelig og beskrivende label. Beskrivelsen (andrelinje) er valgfri tilleggsinfo, ikke en erstatning for en klar label. "Norge" er bedre enn "NO". |
| 3.3.2 Ledetekster eller instruksjoner | A | Ved flervalg: forklar chip-navigasjonen. arrowHintText kobles via aria-describedby (skjult element) på inputfeltet og forteller skjermleserbrukere at valgte alternativer (chips) nås med piltast. chipsLabel gir chip-gruppen (role=group) et tilgjengelig navn. Send inn begge i multi-modus. |
Håndtert av komponenten (18)
| Kriterium | Nivå | Hva komponenten gjør |
|---|---|---|
| 1.3.1 Informasjon og relasjoner | A | input får role=combobox med aria-autocomplete=list, aria-expanded og aria-controls til listbox. Lista er role=listbox, alternativer role=option. Single: aria-selected=true kun på valgt (øvrige uten attributt, APG). Multi: valgte vises som chips med role=button i en role=group-wrapper (chipsLabel). Skjult select gir semantisk form-verdi. |
| 1.3.2 Meningsfull rekkefølge | A | Chips, felt, liste og feilmelding følger naturlig rekkefølge i DOM. |
| 1.3.3 Sensoriske egenskaper | A | Valgt tilstand vises med checkmark (struktur) i tillegg til bakgrunn — i både single og flervalg, ikke farge alene. |
| 1.4.1 Bruk av farge | A | Valgt og aktivt alternativ kommuniseres med checkmark (begge moduser) og bakgrunn, ikke farge alene. Feiltilstand bruker tekst, ramme og aria-invalid. |
| 1.4.4 Endre tekststørrelse | AA | Relative enheter — skalerer korrekt ved 200 % zoom. |
| 1.4.10 Omflyt | AA | Reflower korrekt ned til 320px viewport. Chips brytes over flere linjer. |
| 1.4.11 Kontrast for ikke-tekstlig innhold | AA | Ramme, fokusindikator og aktivt alternativ oppfyller 3:1 kontrastkrav. |
| 1.4.12 Tekstavstand | AA | Tåler økt line-height, bokstav- og ordavstand uten tap av innhold. |
| 1.4.13 Innhold ved hover eller fokus | AA | Lista lukkes forutsigbart med Escape og klikk utenfor; ingen hover-only innhold som forsvinner utilsiktet. |
| 2.1.1 Tastatur | A | Fullt opererbart med tastatur: piltaster navigerer i lista (virtual focus via aria-activedescendant), Enter velger, Escape lukker, Backspace fjerner chip, piltast navigerer mellom chips. |
| 2.1.2 Ingen tastaturfelle | A | Fokus blir på inputfeltet og kan navigeres ut med Tab/Shift+Tab. Ingen tastaturfelle. |
| 2.4.3 Fokusrekkefølge | A | Ett tab-stopp på feltet; chips nås med piltast (radiogruppe-modell), ikke egne tab-stopp. Naturlig DOM-rekkefølge. |
| 2.4.7 Synlig fokus | AA | Tydelig fokusindikator på inputfeltet og på toggle-knappen ved tastaturfokus. |
| 2.5.8 Målstørrelse (minimum) | AA | Toggle-knapp og alternativer oppfyller minimum 44x44px klikkflate. |
| 3.2.1 Ved fokus | A | Fokus alene trigger ingen kontekstendring — lista åpnes ved skriving, klikk eller piltast, ikke ved fokus. |
| 3.2.2 Ved inndata | A | Valg trigger ingen automatisk kontekstendring med mindre onChange eksplisitt gjør det. |
| 4.1.2 Navn, rolle, verdi | A | APG combobox-mønster: role=combobox/listbox/option, aria-expanded, aria-controls, aria-activedescendant, aria-selected, aria-multiselectable. Chips er role=button i en role=group-wrapper (gyldig navn/rolle, ikke orphan options). Piltast-hint kobles via aria-describedby (skjult element), additivt sammen med ix-field sin describedby. Tilgjengelig navn fra label. |
| 4.1.3 Statusmeldinger | AA | To role=status live-regioner: synlig no-hits-melding ved 0 treff, og en skjult (sr-only) region som annonserer antall treff (resultsText, {n}) ved filtrering — debounced og kun når antallet endres, så skjermleseren ikke oversvømmes. Feilmelding annonseres via ix-field sin aria-live=polite. |
Ikke relevant (30)
| Kriterium | Nivå | Hvorfor ikke relevant |
|---|---|---|
| 1.1.1 Ikke-tekstlig innhold | A | Checkmark og chevron er dekorative CSS-masker med aria-hidden; ingen informasjonsbærende bilder. |
| 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.4 Visningsretning | AA | Ingen fast orientering — tilpasser seg visningsretning. |
| 1.3.5 Identifiser formål med inndata | AA | Ikke et felt for personlig informasjon — autocomplete gjelder ikke. |
| 1.4.2 Styring av lyd | A | Ingen lydelementer. |
| 1.4.5 Bilder av tekst | AA | Ingen bilder av tekst. |
| 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 bevegelsesbaserte gester — alt betjenes med enkle trykk/klikk. |
| 2.5.2 Avbryt peker | A | |
| 2.5.4 Bevegelsesaktivering | A | Ingen bevegelsesaktivering. |
| 2.5.6 Samtidige inndatamekanismer | A | |
| 2.5.7 Drabevegelser | A | Ingen drag-and-drop. |
| 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
ComboboxProps
| Prop | Type | Påkrevd | Standard | Beskrivelse |
|---|---|---|---|---|
label | string | Nei* | Synlig labeltekst. Anbefalt fremfor ariaLabel | |
ariaLabel | string | Nei* | Skjult label for skjermlesere. *Enten label eller ariaLabel må settes | |
options | ComboboxOption[] | Ja | Alternativene i lista | |
noHitsText | string | Ja | Tekst i lista når filteret gir 0 treff (i18n) | |
multiple | boolean | Nei | false | Flervalg med chips |
value | string | string[] | Nei | Kontrollert verdi. string i single, string[] i multi | |
defaultValue | string | string[] | Nei | Ukontrollert startverdi. Virker kun ved mount | |
onChange | (value: string | string[]) => void | Nei | Kalles ved valg/avmarkering/fjerning. Får string i single ('' når tomt), string[] i multi | |
placeholder | string | Nei | Placeholder i inputfeltet | |
description | string | Nei | Hjelpetekst under label | |
errorMessage | string | Nei | Feilmelding. Trigger aria-invalid når den har innhold | |
disabled | boolean | Nei | Deaktiverer feltet | |
readOnly | boolean | Nei | Skrivebeskyttet felt | |
required | boolean | Nei | Markerer feltet som påkrevd | |
toggleLabel | string | Nei | aria-label på chevron-knappen (i18n) | |
removeChipLabel | string | Nei | Suffiks på chip-ens aria-label, f.eks. "fjern" (i18n, multi) | |
chipsLabel | string | Nei | aria-label på chip-gruppen (role="group"), f.eks. "Valgte alternativer" (i18n, multi) | |
arrowHintText | string | Nei | Skjult hint (aria-describedby) som forklarer chip-navigasjon (i18n, multi) | |
resultsText | string | Nei | Mal for skjermleser-annonsering av antall treff. {n} byttes med antallet, f.eks. "{n} alternativer" (i18n) | |
name | string | Nei | Navn på skjult <select> for form-innsending | |
className | string | Nei | CSS-klasse på ytterste wrapper (.ix-field) | |
ref | Ref<IxCombobox> | Nei | Ref videresendes til <ix-combobox>-elementet |
ComboboxOption
| Prop | Type | Påkrevd | Beskrivelse |
|---|---|---|---|
value | string | Ja | Verdien som sendes ved valg |
label | string | Ja | Teksten som vises for alternativet |
description | string | Nei | Valgfri andrelinje under label |
disabled | boolean | Nei | Gjør alternativet utilgjengelig for valg |
Tilpasning med CSS
Tilgjengelige klasser og selektorer
| Element | Selektor |
|---|---|
| Rot | .ix-combobox |
| Chips-wrapper | .ix-combobox__chips |
| Toggle-knapp | .ix-combobox__toggle |
| Listbox | .ix-combobox__listbox |
| Alternativ | .ix-combobox__option |
| Checkmark | .ix-combobox__option-check |
| Ingen treff | .ix-combobox__no-hits |
Relatert
- Combobox i ren HTML — full gjennomgang av HTML-markup, forhåndsvalg og form-innsending
- Select — for enkelt valg fra kort/mellomlang liste uten søk
- Chip — chip-stilen som gjenbrukes for valgte alternativer i flervalg