Przejdź do treści

Combobox

Stabilny

Pole tekstowe z filtrowaną listą do wyboru spośród większej liczby opcji, niż wygodnie pomieści lista wyboru.

Instalacja

$ pnpm dlx shadcn@latest add https://www.prfct.dev/r/combobox.json

Użycie

import {
  Combobox,
  ComboboxContent,
  ComboboxEmpty,
  ComboboxInput,
  ComboboxItem,
  ComboboxList,
} from "@/components/ui/combobox"
const frameworks = ["Next.js", "Remix", "Astro", "SvelteKit"]

<Combobox items={frameworks}>
  <ComboboxInput placeholder="Search frameworks…" />
  <ComboboxContent>
    <ComboboxEmpty>No frameworks found.</ComboboxEmpty>
    <ComboboxList>
      {(item) => (
        <ComboboxItem key={item} value={item}>
          {item}
        </ComboboxItem>
      )}
    </ComboboxList>
  </ComboboxContent>
</Combobox>

Przekaż komponentowi głównemu pełną tablicę items, a listę renderuj funkcją: Base UI filtruje pozycje w trakcie pisania i wywołuje funkcję tylko dla trafień. ComboboxEmpty pojawia się automatycznie, gdy nic nie pasuje.

Przykłady

Czyszczenie wartości

Gdy pole ma wartość, showClear zamienia strzałkę na przycisk czyszczenia. Dodawaj go zawsze, gdy pusta wartość jest poprawna — zadanie bez przypisanej osoby, brak filtra — żeby nikt nie musiał zaznaczać tekstu i go kasować.

Grupy

Grupy to po prostu pozycje z własną tablicą items. Renderuj je za pomocą ComboboxGroup, nagłówka ComboboxLabelComboboxCollection dla elementów grupy; podczas filtrowania grupa zostaje na liście tylko wtedy, gdy ma trafienia. InputGroupAddon przekazany jako element potomny dodaje ikonę na początku pola.

Wybór wielokrotny

Wybrane wartości stają się chipami wewnątrz pola. useComboboxAnchor zwraca ref do kontenera chipów, dzięki czemu lista jest wyrównana do całego pola, a nie tylko do inputu tekstowego. autoHighlight sprawia z kolei, że w trakcie pisania Enter wybiera pierwsze trafienie.

Rozbudowane opcje

Opcja może pokazywać wszystko, co pomaga rozpoznać właściwą — awatar i adres e-mail odróżnią dwie osoby o tym samym imieniu i nazwisku. Gdy wartościami są obiekty, itemToStringLabel decyduje, co trafia do pola, a itemToStringValue — co wysyła formularz.

Przycisk jako wyzwalacz

Gdy pole ma wyglądać jak przycisk — przełącznik repozytoriów, filtr na pasku narzędzi — wyrenderuj ComboboxTrigger jako Button, a pole tekstowe przenieś do popupu z showTrigger={false}.

Gdy dane są na serwerze, ustaw filter={null}, żeby wyłączyć lokalne filtrowanie w Base UI, pobieraj wyniki w onInputValueChange i przekazuj je z powrotem jako items. Nie wysyłaj zapytania po każdym znaku (debounce), ignoruj nieaktualne odpowiedzi i pokazuj, że wyszukiwanie trwa — tutaj ikona lupy zamienia się w spinner.

Wytyczne

Kiedy używać

  • Przy długich listach — krajów, osób, stref czasowych, repozytoriów — gdzie wpisanie kilku liter jest szybsze niż przewijanie.
  • Gdy użytkownicy zwykle wiedzą, czego szukają.
  • Do wyboru kilku wartości z długiej listy: etykiet, odbiorców, tagów.

Kiedy nie używać

  • Przy mniej niż około piętnastu opcjach, które użytkownicy raczej przeglądają, niż przeszukują — użyj Select.
  • Do dowolnego tekstu z opcjonalnymi podpowiedziami, np. w polu wyszukiwania — użyj Input z własną listą sugestii; wartością Comboboxa może być tylko jedna z jego pozycji.
  • Do uruchamiania poleceń — użyj palety Command.

Dopasowywanie

Dopasowuj w dowolnym miejscu etykiety, nie tylko od początku (york powinno znaleźć New York), i ignoruj wielkość liter oraz znaki diakrytyczne (krakow powinno znaleźć Kraków — przekaż locale, gdy dane nie są po angielsku). Najbardziej prawdopodobne trafienia pokazuj na początku, a stan pusty formułuj konkretnie: powiedz, czego nie znaleziono, i jeśli to możliwe — co zrobić zamiast tego.

Nikt z zespołu nie pasuje do „Grce”Sprawdź pisownię albo zaproś tę osobę e-mailem.
Dobrze.Konkretny stan pusty, który przytacza zapytanie i podpowiada kolejny krok.
Brak danych
Źle.Sam komunikat bez kontekstu każe się domyślać, czy lista w ogóle działa.

Dostępność

Pole ma role="combobox", aria-expandedaria-autocomplete="list" oraz steruje rozwijaną listą listbox. Zgodnie z wzorcem ARIA combobox fokus zostaje w polu, a po opcjach przesuwa się podświetlenie.

KlawiszDziałanie
A–Z
Wpisywanie filtruje listę i ją otwiera.
Otwiera listę i przesuwa podświetlenie. Na obu końcach listy podświetlenie wraca do pola.
Enter
Wybiera podświetloną opcję.
Esc
Zamyka listę; tekst w polu zostaje.
Backspace
Przy wyborze wielokrotnym, gdy pole jest puste, usuwa ostatni chip.
Tab
Przenosi fokus do następnej kontrolki i zamyka listę.
  • Opisz pole etykietą. Powiąż widoczny FieldLabelid pola albo użyj aria-label na paskach narzędzi.
  • Informuj o ładowaniu. Gdy wyniki przychodzą z serwera, nadaj spinnerowi dostępną etykietę (komponent Spinner ma domyślnie etykietę Loading) i zadbaj, żeby tekst stanu pustego był zrozumiały.
  • Chipy. Przycisk usuwania w każdym chipie bierze nazwę od chipu — „Usuń Design”, a nie samo „przycisk” — w języku ustawionym przez LocaleProvider. Gdy treść chipu nie jest zwykłym tekstem, przekaż removeLabel. Przyciski usuwania są poza kolejnością tabulacji; z klawiatury chipy usuwa się klawiszem Backspace.
  • Przycisk rozwijania. Strzałka ma etykietę „Pokaż lub ukryj opcje” i jest pomijana przez Tab — to ułatwienie dla myszy, a z klawiatury listę otwiera już samo pole.
  • Krawędzie i obszary klikalne. Obramowanie pola korzysta z tokenu input (3:1, WCAG 1.4.11); opcje mają co najmniej 32 px wysokości.

Dokumentacja API

Combobox

Komponent główny. Nie renderuje żadnego elementu. Przyjmuje wszystkie propsy Combobox.Root z Base UI.

PropTypDomyślnie
items

Wszystkie opcje albo grupy opcji. Filtrowane w trakcie pisania.

any[] | Group[]Brak wartości domyślnej
value / defaultValue

Wybrana wartość — kontrolowana lub początkowa.

Value | Value[] | nullBrak wartości domyślnej
onValueChange

Wywoływana, gdy zmienia się wybór.

(value, details) => voidBrak wartości domyślnej
multiple

Pozwala wybrać kilka wartości; renderuj je jako chipy.

booleanfalse
inputValue / defaultInputValue

Tekst w polu — kontrolowany lub początkowy.

stringBrak wartości domyślnej
onInputValueChange

Wywoływana przy każdym naciśnięciu klawisza — to miejsce na pobieranie wyników z serwera.

(value, details) => voidBrak wartości domyślnej
filter

Własna logika dopasowania. Przekaż null, żeby wyłączyć lokalne filtrowanie przy wyszukiwaniu po stronie serwera.

((item, query) => boolean) | nullBrak wartości domyślnej
filteredItems

Pozycje przefiltrowane z zewnątrz, gdy filtrowaniem sterujesz sam.

any[]Brak wartości domyślnej
autoHighlight

Podświetla pierwsze trafienie w trakcie pisania, więc Enter je wybiera.

boolean | "always"false
openOnInputClick

Otwiera listę po kliknięciu pola.

booleantrue
limit

Ogranicza liczbę renderowanych trafień. -1 oznacza brak limitu.

number-1
itemToStringLabel / itemToStringValue

Zamienia wartości-obiekty na tekst w polu i na wartość wysyłaną z formularzem.

(value) => stringBrak wartości domyślnej
locale

Ustawienia regionalne do dopasowywania bez względu na znaki diakrytyczne i wielkość liter.

Intl.LocalesArgumentBrak wartości domyślnej
name / required / disabled / readOnly

Propsy formularza i interakcji, jak w natywnych polach.

string / booleanBrak wartości domyślnej
modal

Gdy lista jest otwarta, blokuje przewijanie strony i interakcję poza nią.

booleanfalse

ComboboxInput

Pole tekstowe renderowane wewnątrz Input Group. Elementy potomne trafiają do grupy — np. InputGroupAddon z ikoną.

PropTypDomyślnie
showTrigger

Pokazuje przycisk ze strzałką, który rozwija i zwija listę.

booleantrue
showClear

Pokazuje przycisk czyszczenia, gdy pole ma wartość.

booleanfalse
disabled

Wyłącza pole i jego przyciski.

booleanfalse
className

Trafia do grupy pola — ustawiaj nim szerokość.

stringBrak wartości domyślnej

ComboboxContent

Pozycjonowany popup z listą.

PropTypDomyślnie
anchor

Element, do którego popup jest wyrównany — przy wyborze wielokrotnym kontener chipów.

RefObject<Element>Brak wartości domyślnej
side

Preferowana strona względem kotwicy.

"top" | "bottom" | "left" | "right""bottom"
sideOffset

Odstęp od kotwicy w pikselach.

number6
align

Wyrównanie wzdłuż wybranej strony.

"start" | "center" | "end""start"

ComboboxList, ComboboxItem, ComboboxEmpty

PropTypDomyślnie
ComboboxList children

Renderuje każdą przefiltrowaną pozycję lub grupę.

ReactNode | (item, index) => ReactNodeBrak wartości domyślnej
ComboboxItem valuewymagany

Wartość, którą reprezentuje opcja.

anyBrak wartości domyślnej
ComboboxItem disabled

Uniemożliwia wybranie opcji.

booleanfalse
ComboboxEmpty children

Wyświetlane tylko wtedy, gdy nic nie pasuje.

ReactNodeBrak wartości domyślnej

Grupy

ComboboxGroup przyjmuje items grupy; ComboboxLabel nadaje jej tytuł; ComboboxCollection renderuje jej elementy funkcją; ComboboxSeparator oddziela grupy.

Chipy

ComboboxChips to pole z chipami do wyboru wielokrotnego (podepnij do niego ref z useComboboxAnchor()), ComboboxValue renderuje wybrane wartości funkcją, ComboboxChip pokazuje jedną wartość z przyciskiem usuwania (showRemove, domyślnie true; removeLabel zastępuje jego dostępną nazwę), a ComboboxChipsInput to input tekstowy wewnątrz tego pola.

ComboboxTrigger i ComboboxValue

ComboboxTrigger otwiera listę z własnego elementu — użyj render, żeby był nim Button. ComboboxValue renderuje etykietę bieżącej wartości.