Gå til hovedinnhold
KOMPONENTER

Multi select

npmv5.3.4

MultiSelect lar brukeren velge ett eller flere elementer fra en liste med valg

npm install @entur/dropdown
@import '@entur/dropdown/dist/styles.css';

Migrering fra v4 -> v5

Bruk

MultiSelect er en komponent som lar brukeren velge ett eller flere elementer fra en liste. Komponenten viser frem en liste med valg bassert på items-prop-en, der items kan være en liste med string eller objekter med value, label og icons - eller en blanding av disse. For å dekke situasjoner der valgalternaltiver kommmer fra et API eller lignende støtter items også synkrone og asynkrone funksjoner som returnerer samme type liste som items aksepterer.

Når brukeren velger noe dukker valget opp som en Chip i inputfeltet. MultiSelect tilbyr også et søkefelt for filtrering av valg, filtreringen her kan overstyres gjennom itemFilter-prop-en – se Egendefinert filtreringsfunksjon for mer info.

Kom i gang

MultiSelect har tre påkrevde props: label, items og selectedItems. I tillegg har den også onChange som ikke er påkrevd, men som er nødvendig for å gjøre komponenten interaktiv.

label er feltets navn og beskriver hva du velger. items tar inn listen med valgalternaltiver, se Liste med valgalternaltiver for mer info. selectedItems og onChange jobber sammen for å holde styr på state for valgte elementer. selectedItems skal være av typen NormalizedDropdownItemType[] (Obs: tom liste, ikke null hvis ingen er valgt) og onChange skal være en funksjon som tar inn alle valgte elementer og oppdaterer verdien på selectedItems til denne listen. Se Standard MultiSelect-eksemplet for å se dette i praksis.

// Definition of NormalizedDropdownItemType
type NormalizedDropdownItemType<ValueType = string> = 
      { label: string, value: ValueType, icons?: React.ComponentType<any>[] }

Siden NormalizedDropdownItemType er en generisk type så kan value være hvilken som helst type. TypeScript vil da også gi deg riktig type ut i onChange. Den er satt til standard som string da dette er vanligste praksis.

Liste med valgalternaltiver

Listen med valgalternaltiver sendes inn gjennom items-prop-en. items har typen PotentiallyAsyncDropdownItems som vil si den støtter tre typer input: liste med DropdownItemType, synkrone funksjoner og asynkrone funksjoner – de to siste kan du lese mer om under Hente valgalternaltiver fra nettverkskall.

DropdownItemType er enten en string eller et objekt med label, value og valgfritt icons – se under.

// Definition of DropdownItemType
type DropdownItemType<ValueType = string> = 
      string |
      { label: string, value: ValueType, icons?: React.ComponentType<any>[] }

Disse kan også blandes slik at følgende også vil være et gyldig items-input:

// Valid mixed type items input
const dropdownItems = [
  "choice1",
  { label: "Second choice", value: "choice2" },
  { lable: "Third choice", value: "choice3", icons: [FunnyIcon1, FunnyIcon2] }
]

Egendefinert filtreringsfunksjon

Som standard er søkefiltreringen bassert på en enkel regex som sjekker om input-et er en del av valgalternaltivet, ønsker du å endre denne kan du skrive din egen filtreringsfunksjon til MultiSelect gjennom prop-en itemFilter. Dette kan være nyttig hvis du f.eks ønsker å implementere fuzzy search eller ignorere noen tegn fra input-et når du filtrerer. itemFilter tar inn en funksjon med item (valgalternaltivet som skal sjekkes mot filtreringen) og inputValue (det bruker for øyeblikket har skrevet inn i inputfeltet) som input. Funksjonen skal returnere true eller false avhengig av om gjeldende item skal være med i listen over valg eller ikke.

Se eksempel på dette under MultiSelect med egendefingert filtreringsfunksjon-eksempelet.

Hente valgalternaltiver fra nettverkskall

Hvis listen din med valg skal hentes fra et API eller lignende er det mulig å sende inn en memoisert funksjon til items i stedet for en liste med valg. Denne funksjonen kan enten være synkron eller asynkron og må enten returnere en liste med DropdownItemType direkte eller gjennom et Promise. OBS: du må huske å memoisere funksjonen ved å bruke React.useCallback, ellers vil den kjøre funksjonen din oftere enn nødvendig!

items-funksjonen kan også bruke inputValue -verdien som sendes inn å gjøre f.eks en query mot et API-et. I disse tilfellene kan prop-en debounceTimeout være nyttig hvis du ønsker å øke eller minke tiden det ventes før et nytt kall mot funksjonen skal kjøres etter brukeres slutter å skrive.

For å avbryte utdaterte kall og hindre 'state update of unmounted component' kan du bruke abortControllerRef som sendes inn som andre argument til funksjonen. abortControllerRef.current.signal inneholder et signal som sier fra når asynkrone kall bør avbrytes og er støttet ut av boksen i f.eks fetch og axios. Les mer om AbortController på Mozilla sine sider og se eksempel på alt i bruk under MultiSelect med valg fra nettverkskall.

Oppsummerings-chip når mange elementer er valgt

For å unngå at skjemaelementet blir for stort vil chip-ene som viser hva som er valgt samles til én felles oppsummerings-chip når antallet overstiger verdien satt i maxChips – denne er som standard satt til 10. Se et eksempel på dette under Endre når oppsummerings-chip vises

Universell utforming

Kommer info om dette snart

Retningslinjer

Kommer snart

Eksempler

Standard MultiSelect

Her finner du en MultiSelect med standard-props.

() => {
const [selected, setSelected] = React.useState([])
return (
<MultiSelect
label="Velg by"
items={cities}
selectedItems={selected}
onChange={setSelected}
/>
)
}

MultiSelect med egendefinert filtreringsfunksjon

I dette eksempelet brukes en fuzzyMatch-implementasjon til å utføre en mer tilgivende filtrering av de tilgjengelige valgene.

() => {
const [selected, setSelected] = React.useState([])
return (
<MultiSelect
label="Fuzzy search filter"
items={cities}
selectedItems={selected}
onChange={setSelected}
itemFilter={(item, inputValue) =>
fuzzyMatch(inputValue, item.label) > 0.5
}
/>
)
}

MultiSelect med valg fra nettverkskall

Her har vi en eksempelfunksjon fetchItems som bruker abortControllerRef-argumentet og henter inn data fra et test-API. Denne funksjonen settes så inn i items-prop-en og vi får data fra det eksterne API-et listet opp når data-en er mottatt.

() => {
// Husk å bruke useCallback for å unngå at funksjonen kjøres oftere enn nødvendig
const fetchItems = React.useCallback(async (_, abortControllerRef) => {
try {
const response = await fetch(
`https://dummyjson.com/products/categories`,
// Bruk signalet fra abortController for å avbryte utdaterte kall
{ signal: abortControllerRef.current.signal },
)
const data = await response.json()
if (data.message !== undefined) return [data.message]
return data
} catch (error) {
// AbortError må sendes videre til komponenten for å håndtere cleanup riktig
if (error && error.name === 'AbortError') throw error
console.error('noe galt')
return []
}
}, [])
const [selected, setSelected] = React.useState([])
return (
<MultiSelect
label="Extenal API list"
items={fetchItems}
selectedItems={selected}
onChange={setSelected}
/>
)
}

Søkbar dropdown med valg fra nettverkskall bassert på tekstinput

Her har vi en eksempelfunksjon fetchItems som henter inn data fra et test-API. fetchItems tar inn nåværende inputValue og abortControllerRef og bruker det til å gjøre en query mot API-et. Denne funksjonen settes så inn i items-prop-en og vi får data fra det eksterne API-et listet opp med query bassert på det som skrives inn. Merk at itemFilter skrues av gjennom () => true slik at all filtrering skjer gjennom API-kallet.

() => {
// Husk å bruke useCallback for å unngå at funksjonen kjøres oftere enn nødvendig
const fetchItems = React.useCallback(
async (inputValue, abortControllerRef) => {
try {
const response = await fetch(
`https://dummyjson.com/products/search?q=${inputValue}&limit=15&select=title`,
// Bruk signalet fra abortController for å avbryte utdaterte kall
{ signal: abortControllerRef.current.signal },
)
const data = await response.json()
if (data.message !== undefined) return [data.message]
const processedData = data.products.map(item => {
return { label: item.title, value: item.id }
})
return processedData
} catch (error) {
// AbortError må sendes videre til komponenten for å håndtere cleanup riktig
if (error && error.name === 'AbortError') throw error
console.error('noe galt')
return []
}
},
[],
)
const [selected, setSelected] = React.useState([])
return (
<MultiSelect
label="Extenal API list"
items={fetchItems}
selectedItems={selected}
onChange={setSelected}
// Vi skrur av itemFilter slik at filtrering skjer gjennom API-kallet
itemFilter={() => true}
/>
)
}

Slett tekstinput etter valg

For å slette tekstinput-et etter at et element er valgt kan du burke prop-en ´clearInputOnSelect´.

() => {
const [selected, setSelected] = React.useState([])
return (
<MultiSelect
label="Reset input on select"
items={cities}
selectedItems={selected}
onChange={setSelected}
clearInputOnSelect
/>
)
}

Endre når oppsummerings-chip vises

Du kan endre hva som er maks antall valgte-elementer-chips som vises i inputfeltet med prop-en maxChips.

() => {
const [selected, setSelected] = React.useState([
{ label: 'Oslo', value: 'Oslo' },
{ label: 'Bergen', value: 'Bergen' },
{ label: 'Kristiansand', value: 'Kristiansand' },
{ label: 'Kristiansund', value: 'Kristiansund' },
])
return (
<MultiSelect
label="Summery chip on 4 selected"
items={cities}
selectedItems={selected}
onChange={setSelected}
maxChips={3}
/>
)
}

Tilgjengelige props

MultiSelect

import { MultiSelect } from '@entur/dropdown';
NavnTypeDefault-verdiBeskrivelse
labelstring

Beskrivende tekst som forklarer feltet

itemsPotentiallyAsyncDropdownItemType<ValueType>

Tilgjengelige valg i MultiSelect

selectedItemsNormalizedDropdownItemType<ValueType>[]

Elementer som er valgt blant ‘items’. Bruk tom liste for ingen valgte

onChange?((selectedItems: NormalizedDropdownItemType<ValueType>[]) => void | Dispatch<SetStateAction<NormalizedDropdownItemType<ValueType>[]>>)

Callback med alle valgte verdier. Bruk denne til å oppdatere selectedItems-listen

itemFilter?((item: NormalizedDropdownItemType<ValueType>, inputValue: string ) => boolean) Regex-test som sjekker om item.label inneholder input-teksten

Filtreringen som brukes når man skriver inn tekst i inputfeltet

variant?VariantType

Hvilken valideringsvariant som gjelder

feedback?string

Valideringsmelding, brukes sammen med variant

disabled?boolean

Om dropdown-en er deaktivert

readOnly?boolean

Om dropdown-en er i read-only modus

clearable?boolean true

Om en knapp for å fjerne alle valg skal vises

placeholder?string

Placeholder-tekst når ingenting er satt

loadingText?string "Laster inn …"

En tekst som beskriver hva som skjer når man venter på items

noMatchesText?string "Ingen treff for søket"

Tekst som kommer opp når det ikke er noe treff på filtreringsøket

hideSelectAll?boolean false

Skjuler «Velg alle» fra listen med valg

debounceTimeout?number 250

Antall millisekunder man venter før man kaller en potensiell items-funksjon

maxChips?number 10

Maks antall individuelle valgt-element-tags i MultiSelect-en før de blir til en samle-tag

prepend?ReactNode

Tekst eller ikon som kommer før MultiSelect

clearInputOnSelect?boolean false

Resetter input etter at et element er valgt i listen

selectOnTab?boolean

Lar brukeren velge ved å “tab-e” seg ut av komponenten

selectOnBlur?boolean

@deprecated Bruk selectOnTab i stedet

Lar brukeren velge ved å “tab-e” seg ut av komponenten

style?CSSProperties
listStyle?{ [key: string]: any; }

Styling som sendes ned til MultiSelect-lista

className?string

Ekstra klassenavn

labelSelectAll?string "Velg alle"

Teksten som vises for «Velg alle»-elementet i listen

labelAllItemsSelected?string "Alle valgt"

Teksten som vises for «Velg alle»-elementet i listen

labelClearAllItems?string "Fjern valgte"

Skjermleser-tekst som for å fjerne alle valg

labelTooltip?ReactNode

En tooltip som gir ekstra info om inputfeltet

ariaLabelRemoveSelected?string "trykk for å fjerne valg"

Tekst for skjemleser på knapper for å fjerne valgt element

ariaLabelChosenPlural?string "valgte"

Tekst for skjemleser for å indikere at et element er valgt

ariaLabelCloseList?string "Lukk liste med valg"

Tekst for skjemleser for knapp som lukker listen med valg

ariaLabelOpenList?string "Åpne liste med valg"

Tekst for skjemleser for knapp som åpner listen med valg

ariaLabelJumpToInput?string `${selectedItems.length} valgte elementer, trykk for å hoppe til tekstfeltet`

Tekst for skjemleser for å hoppe til input-feltet

ariaLabelChosenSingular?string 'valgt'

Ord for at et element er valgt i entall eks. ‘Element 1, valgt

ariaLabelSelectedItem?string ', valgt element, trykk for å fjerne'

Tekst for skjermleser som beskriver statusen til et element som valgt

Rediger denne siden på Bitbucket