Site settings
Change the appearance of the site to suit your preferences
Autocomplete (New Combobox)
A Autocomplete is a dropdown list you can search in and filter.
This replaces Combobox which which will deprecated eventually.
A simple autocomplete
Map out a list of items. Pass item to each AutocompleteItem.
() => { const countries = [ { value: "no", label: "Norge" }, { value: "se", label: "Sverige" }, { value: "dk", label: "Danmark" }, { value: "fi", label: "Finland" }, { value: "de", label: "Tyskland" }, { value: "fr", label: "Frankrike" }, { value: "nl", label: "Nederland" }, ]; return ( <Autocomplete label="Velg land"> {countries.map((item) => ( <AutocompleteItem item={item} key={item.value}>{item.label}</AutocompleteItem> ))} </Autocomplete> ); };
Controlled autocomplete
Use props value and onValueChange to control combobox value.
Use props inputvalue and onInputValueChange to control input value
() => { const countries = [ { value: "no", label: "Norge" }, { value: "se", label: "Sverige" }, { value: "dk", label: "Danmark" }, { value: "fi", label: "Finland" }, { value: "de", label: "Tyskland" }, { value: "fr", label: "Frankrike" }, { value: "nl", label: "Nederland" }, ]; const [value, setValue] = React.useState<string[]>([]); const [inputValue, setInputValue] = React.useState(""); return ( <Autocomplete label="Velg land" onValueChange={({ value }) => setValue(value)} onInputValueChange={({ inputValue }) => setInputValue(inputValue)} inputValue={inputValue} variant="floating" value={value} > {countries.map((item) => ( <AutocompleteItem item={item} key={item.value}> {item.label} </AutocompleteItem> ))} </Autocomplete> ); }
Multiple items example
Pass multiple to allow multiple items to be selected
() => { const countries = [ { value: "no", label: "Norge" }, { value: "se", label: "Sverige" }, { value: "dk", label: "Danmark" }, { value: "fi", label: "Finland" }, { value: "de", label: "Tyskland" }, { value: "fr", label: "Frankrike" }, { value: "nl", label: "Nederland" }, ]; const [selectedCountries, setSelectedCountries] = React.useState([]); return ( <Stack gap="2"> <Wrap gap="2"> {selectedCountries.map((country) => ( <Badge key={country.value}>{country.label}</Badge> ))} </Wrap> <Autocomplete label="Velg land" onValueChange={({ items }) => setSelectedCountries(items)} value={selectedCountries.map(({value}) => value)} multiple > {countries.map((item) => ( <AutocompleteItem item={item} key={item.value}> {item.label} </AutocompleteItem> ))} </Autocomplete> </Stack> ); }
Variants
Comes with variants core and floating
() => { const countries = [ { value: "no", label: "Norge" }, { value: "se", label: "Sverige" }, { value: "dk", label: "Danmark" }, ]; return ( <Flex gap="4"> <Autocomplete label="Velg land (Core)" variant="core" > {countries.map((item) => ( <AutocompleteItem item={item} key={item.value}>{item.label}</AutocompleteItem> ))} </Autocomplete> <Autocomplete label="Velg land (floating)" variant="floating"> {countries.map((item) => ( <AutocompleteItem item={item} key={item.value}>{item.label} </AutocompleteItem> ))} </Autocomplete> </Flex> ); };
Rendering custom items and sections
Use AutocompleteItemGroup and AutocompleteItemGroupLabel to group items into sections.
Pass leftIcon to Autocomplete for icon in the input
Pass emptyLabel to customize what is shown when no results are found.
Simply pass whatever you want into ComboboxItem to create custom items.
() => { const popularSearches = [ { label: "Skøyen", subLabel: "Stasjon i Oslo", value: "skoyen", }, { label: "Jernbanetorget", subLabel: "Oslo sentrum", value: "jernbanetorget", }, { label: "Drammen", subLabel: "Drammen stasjon", value: "drammen", }, ]; const myPosition = { label: "Min posisjon", value: "min-posisjon", }; return ( <Autocomplete label="Hvor reiser du til?" leftIcon={<DestinationOutline24Icon />} emptyLabel={ <Flex color="text.secondary" justifyContent="center" py="4"> Ingen treff. Prøv å søke etter en stasjon eller adresse. <FrownFill24Icon /> </Flex> } > <AutocompleteItem item={myPosition} py="2"> {myPosition.label} <PositionOutline24Icon /> </AutocompleteItem> <AutocompleteItemGroup> <AutocompleteItemGroupLabel>Populære søk</AutocompleteItemGroupLabel> {popularSearches.map((item) => ( <AutocompleteItem item={item} key={item.value}> <Stack> <Text variant="sm">{item.label}</Text> <Text variant="xs">{item.subLabel}</Text> </Stack> <Flex gap="1"> <SubwayOutline24Icon /> <TrainOutline24Icon /> </Flex> </AutocompleteItem> ))} </AutocompleteItemGroup> </Autocomplete> ); };
Invalid combobox
Pass invalid and errorText to show invalid combobox with error message
() => { const countries = [ { value: "no", label: "Norge" }, { value: "se", label: "Sverige" }, { value: "dk", label: "Danmark" }, ]; return ( <Autocomplete label="Velg land" invalid={true} errorText="Feil valg"> {countries.map((item) => ( <AutocompleteItem item={item} key={item.value}>{item.label}</AutocompleteItem> ))} </Autocomplete> ); };
Complex example with async data
Implemented travel search with controlled autocompletes.
- Use
onFlipcallback with flipAriaLabelto add a flip-button between two inputs - Pass
filteredExternallyto Autocomplete to not use the internal filtering. Useful for async data filtering to an external API - Pass
loadingfor loading state inside the autocomplete dropdown.
() => { const useMockDestinationQuery = (searchQuery: string) => { return useSwr( [searchQuery, "destinations"], async () => { await new Promise((resolve) => setTimeout(resolve, 250)); return [ { label: "Oslo S", subLabel: "Oslo", value: "oslo-s" }, { label: "Bergen", subLabel: "Bergen stasjon", value: "bergen" }, { label: "Trondheim", subLabel: "Trondheim stasjon", value: "trondheim", }, { label: "Tromsø", subLabel: "Tromsø stasjon", value: "tromso" }, ].filter((destination) => destination.label.toLowerCase().includes(searchQuery.toLowerCase()), ); }, { keepPreviousData: true, }, ); }; const [searchQueryFrom, setSearchQueryFrom] = React.useState(""); const [searchQueryTo, setSearchQueryTo] = React.useState(""); const [from, setFrom] = React.useState(); const [to, setTo] = React.useState(); const { data: destinationsFrom, isLoading: isLoadingFrom } = useMockDestinationQuery(searchQueryFrom); const { data: destinationsTo, isLoading: isLoadingTo } = useMockDestinationQuery(searchQueryTo); return ( <AttachedInputs onFlip={() => { setFrom(to); setTo(from); setSearchQueryFrom(searchQueryTo); setSearchQueryTo(searchQueryFrom); }} flipAriaLabel="Bytt avgang og avreise" orientation={{ xlDown: "vertical", xl: "horizontal" }} > <Autocomplete label="Hvor reiser du fra?" leftIcon={<DestinationOutline24Icon />} variant="floating" filteredExternally loading={isLoadingFrom} onInputValueChange={({ inputValue }) => setSearchQueryFrom(inputValue)} onValueChange={({ items }) => setFrom(items[0])} value={from?.id} inputValue={searchQueryFrom} > <AutocompleteItemGroup> <AutocompleteItemGroupLabel>Tidligere søk</AutocompleteItemGroupLabel> {destinationsFrom?.map((item) => ( <AutocompleteItem item={item} key={item.value}> <Stack> <Text variant="sm">{item.label}</Text> <Text variant="xs">{item.subLabel}</Text> </Stack> <Flex gap="1"> <SubwayOutline24Icon /> <TrainOutline24Icon /> </Flex> </AutocompleteItem> ))} </AutocompleteItemGroup> </Autocomplete> <Autocomplete label="Hvor reiser du til?" leftIcon={<DestinationOutline24Icon />} variant="floating" filteredExternally loading={isLoadingTo} onInputValueChange={({ inputValue }) => setSearchQueryTo(inputValue)} onValueChange={({ items }) => setTo(items[0])} value={to?.id} inputValue={searchQueryTo} > <AutocompleteItemGroup> <AutocompleteItemGroupLabel>Tidligere søk</AutocompleteItemGroupLabel> {destinationsTo?.map((item) => ( <AutocompleteItem item={item} key={item.value}> <Stack> <Text variant="sm">{item.label}</Text> <Text variant="xs">{item.subLabel}</Text> </Stack> <Flex gap="1"> <SubwayOutline24Icon /> <TrainOutline24Icon /> </Flex> </AutocompleteItem> ))} </AutocompleteItemGroup> </Autocomplete> </AttachedInputs> ); };
Inside Dialog example
() => { const countries = [ { value: "no", label: "Norge" }, { value: "se", label: "Sverige" }, { value: "dk", label: "Danmark" }, { value: "fi", label: "Finland" }, { value: "de", label: "Tyskland" }, { value: "fr", label: "Frankrike" }, { value: "nl", label: "Nederland" }, ]; return ( <DialogRoot size="md"> <DialogTrigger asChild> <Button size="md">Open autocomplete inside dialog</Button> </DialogTrigger> <DialogContent> <DialogHeader> <DialogTitle>Dialog Title</DialogTitle> </DialogHeader> <DialogBody> <Autocomplete label="Velg land"> {countries.map((item) => ( <AutocompleteItem item={item}>{item.label}</AutocompleteItem> ))} </Autocomplete> </DialogBody> <DialogFooter> <DialogActionTrigger asChild> <Button variant="tertiary">Lukk</Button> </DialogActionTrigger> <DialogActionTrigger asChild> <Button variant="primary">Ok</Button> </DialogActionTrigger> </DialogFooter> </DialogContent> </DialogRoot> ); };