React Multi Select mit Suche, Chips und Bottom Sheet

Ein React Multi Select fängt einfach an: ein Dropdown, eine Checkbox pro Zeile, ein Array im State. Dann kommen echte Daten. Jemand wählt neun Kategorien, und durch die Chips wächst das Feld auf drei Zeilen. Die Liste hat 140 Optionen, und niemand findet „Haustiere“. „Alle auswählen“ erwischt auch Zeilen, die die Suche ausgeblendet hatte. Auf dem Smartphone öffnet sich das Popover genau unter dem Daumen, der es angetippt hat. Dieser Guide zeigt, was eine React Multi Select Komponente können muss, welche Props im Multi Select von Wingo UI (der Bibliothek, die wir bauen) zählen, wie Tastatur und Screenreader funktionieren, wie das Layout auf dem Smartphone aussieht und wann ein Tag Input, eine Combobox oder einfache Checkboxen die bessere Wahl sind.
Was muss ein React Multi Select können?
Ein React Multi Select muss sieben Dinge gut können. Wir haben unseren an dieser Liste geprüft, und sie taugt als Checkliste für jedes Multi Select Dropdown mit Checkbox und Suche:
- Beim Auswählen offen bleiben. Jede Zeile schaltet um, und die Liste bleibt offen, weil Leute meistens mehr als eine Option wählen.
- Die Auswahl als Chips zeigen, die passen. So viele Chips, wie in eine Zeile passen, dann ein „+N“-Chip, damit das Feld seine Höhe behält.
- Entfernen, ohne zu öffnen. Jeder Chip hat sein eigenes x, und Backspace entfernt den letzten.
- Suchen, wenn die Liste lang ist. Kurze Listen brauchen kein Suchfeld, lange sind ohne eins unbrauchbar.
- Alle auswählen und ein Maximum. Alle auswählen für „jede Region“, ein Limit für „bis zu 3 Städte“, beides in der Oberfläche erklärt.
- Absenden wie ein natives Feld. Die Werte landen in
FormData,requiredblockiert ein leeres Absenden, ein Formular-Reset stellt den Standardwert wieder her. - Auf dem Smartphone funktionieren. Große Zeilen, 16px große Schrift, damit iOS nicht zoomt, und eine Ebene, die der Daumen erreicht.
Installier den Multi Select und render ihn:
Das Icon einer Option erscheint in der Zeile und in ihrem Chip. So landen Avatare neben den Namen in einer Auswahl für Zuständige. Optionen können auch Gruppen sein: { label: "Fahrzeuge", items: [...] }.
$ npx wingo-ui@latest add multi-selectWie zeige ich +N, wenn Multi Select Chips überlaufen?
Miss die Chips: Render jeden Chip unsichtbar in einer versteckten Ebene, addiere ihre Breiten nacheinander und hör beim letzten Chip auf, der passt und noch Platz für den +N-Chip lässt. Die beiden naheliegenden Abkürzungen funktionieren nicht. Brechen die Chips in neue Zeilen um, wächst das Feld und schiebt das Formular nach unten. Eine feste Anzahl („zeig 2, dann +N“) verschenkt Platz in einem breiten Feld und läuft in einem schmalen mit langen Labels trotzdem über.
Genau dieses Messen macht maxVisibleChips={0} (der Standard). Ein ResizeObserver beobachtet das Feld und die versteckte Ebene. So passt sich die Anzahl an, wenn sich die Fenstergröße ändert oder eine Webfont spät lädt und die Labels breiter macht. Mindestens ein Chip ist immer zu sehen, notfalls gekürzt, damit das Feld nie nur „+5“ zeigt. Der +N-Chip trägt die versteckten Namen in seinem title, du siehst sie also, wenn du mit der Maus darüberfährst.
Für einen anderen Kompromiss reicht eine Prop:
display="count" passt zu Filterleisten. Dort ist das Feld schmal, und die einzelnen Werte zählen weniger als die Tatsache, dass ein Filter aktiv ist.
Wie ergänze ich Suche und Alle auswählen im Multi Select?
Ergänze die Suche, sobald die Liste mehr als acht Optionen hat, Alle auswählen, wenn „jede Option“ eine echte Wahl ist, und ein Maximum, wenn dein Produkt ein Limit hat. Mit search="auto" (der Standard) erscheint die Suchzeile ab mehr als acht Optionen oder sobald du loadOptions oder creatable übergibst; "always" und "never" überschreiben das. Beim Tippen spielen Groß- und Kleinschreibung und Akzente keine Rolle („zurich“ findet „Zürich“), passende Buchstaben werden fett, und Backspace in der leeren Suche entfernt den letzten Chip. Für Listen, die auf einem Server liegen, bekommt loadOptions die Suchanfrage nach einem debounce von 250ms und ein AbortSignal. Die vorige Anfrage wird abgebrochen, damit eine alte Antwort nie eine neuere überschreibt:
Die letzten 20 Suchanfragen werden gecacht. Tippst du zu einer früheren Anfrage zurück, erscheinen ihre Ergebnisse ohne neuen Request. Die Komponente merkt sich außerdem das Label jeder Option, die sie einmal gesehen hat. Gewählte Werte, die nicht in den aktuellen Ergebnissen stehen, behalten so ihre Chips mit echten Namen. Eine Suche nach „vin“ macht aus dem Chip „Verhandlungsbasis“, den du vorher gewählt hast, keine rohe ID.
selectAll fügt oben eine Zeile hinzu. Sie schaltet nur die sichtbaren Optionen um: Wer nach „neu“ gesucht und Alle auswählen gedrückt hat, meinte die passenden Zeilen. maxSelected={3} begrenzt die Auswahl, deaktiviert am Limit die nicht gewählten Zeilen, und die Fußzeile zeigt „2 of 3 selected“. Sind beide aktiv, stoppt Alle auswählen am Limit.
$ npx wingo-ui@latest add multi-selectWie mache ich einen Multi Select barrierefrei?
Mach das Feld zu einer Combobox, die eine Listbox mit aria-multiselectable steuert, halte den DOM-Fokus aus der Liste heraus und lass die Anzahl vorlesen. Im Multi Select ist das Feld ein Button mit role="combobox", aria-haspopup="listbox", aria-expanded und aria-activedescendant, das auf die markierte Zeile zeigt. Ein Screenreader liest also die Zeile vor, die gerade per Tastatur markiert ist, während der Fokus auf dem Feld bleibt. Ist die Suchzeile sichtbar, wandert der Fokus hinein, und das Suchfeld trägt stattdessen aria-activedescendant. So kommst du auch beim Tippen mit den Pfeiltasten durch die Zeilen. Den Namen des Felds bilden sein Label und die aktuelle Zusammenfassung, ein Screenreader liest also „Abonnierte Kategorien, 3 selected“. Die Anzahl in der Fußzeile steht in einer höflichen Live-Region (aria-live="polite"), damit nach jedem Umschalten die neue Anzahl vorgelesen wird.
Das Tastaturmodell:
- Geschlossen: Enter, Leertaste oder Pfeil nach unten öffnen die Liste, Pfeil nach oben öffnet sie auf der letzten Zeile, Pos1 und Ende öffnen sie am jeweiligen Ende, Backspace entfernt den letzten Chip.
- Offen: Pfeil nach oben und unten bewegen die Markierung und springen vom Ende der Liste an ihren Anfang und umgekehrt, Bild auf und Bild ab springen in großen Schritten, Enter oder Leertaste schalten die markierte Zeile um und lassen die Liste offen, Cmd oder Strg+A wählt alles aus, solange die Liste (nicht die Suche) den Fokus hat, Escape oder Alt+Pfeil nach oben schließen und geben den Fokus ans Feld zurück, Tab schließt und geht weiter.
Die x-Buttons der Chips liegen mit Absicht nicht in der Tab-Reihenfolge. Durch neun Chips zu tabben, um zum nächsten Feld zu kommen, kostet neun Tastendrücke; Backspace auf dem Feld entfernt den letzten Chip mit einem. Für Maus und Touch funktionieren die x-Buttons trotzdem, bei Touch-Eingabe mit größerer Trefferfläche.
Wie funktioniert ein Multi Select auf dem Smartphone?
Unter 768px öffnet der Multi Select ein Bottom Sheet statt des Popovers (responsive ist standardmäßig an). Das Sheet trägt das Label des Felds als Titel, die Zeilen sind 48px hoch mit der Checkbox am Anfang, und eine fixierte Fußzeile enthält „Clear all“ und „Done (3)“. Die Auswahl im Sheet ist ein Entwurf: Done übernimmt sie, Herunterziehen, ein Tipp daneben oder Escape verwerfen sie. Das passt zu dem, was Leute von einem Sheet erwarten: ein Schritt, den sie wieder abbrechen können.
Das Feld selbst wächst auf Touchscreens in der Standardgröße md von 40px auf 44px, und seine Schrift ist auf Smartphones in jeder Größe 16px groß. So zoomt iOS Safari beim Öffnen nicht hinein. Ein Touch-Detail übersieht man leicht: Auf einem Touchscreen bekommt die Suchzeile beim Öffnen der Liste keinen Fokus, denn die Bildschirmtastatur würde die Hälfte der Zeilen verdecken, die die Person antippen wollte. Erst ein Tipp auf die Suchzeile holt die Tastatur hoch. Setz search="always", wenn Tippen der Hauptweg ist, dann bekommt die Suche sofort den Fokus. Unser Guide zum Bottom Sheet erklärt, warum ein Sheet auf kleinen Bildschirmen besser ist als ein Popover.
Wie nutze ich den Multi Select mit react-hook-form und zod?
Pack ihn in einen Controller und validiere das Array. ref und onBlur landen auf dem Button des Felds, also kann react-hook-form ihn fokussieren, wenn die Validierung scheitert:
Ohne Formular-Bibliothek übergibst du name und liest die Hidden Inputs in einer Server Action mit formData.getAll("cities"). Mit required und name blockiert ein leeres Feld das Absenden wie ein natives Select, und die Meldung des Browsers zeigt auf das Feld. Validiere trotzdem auf dem Server: Hidden Inputs lassen sich so leicht bearbeiten wie jedes andere Feld.
Wann nehme ich Multi Select, Tag Input, Combobox oder Checkboxen?
Nimm einen Multi Select für mehrere Werte aus einer bekannten Liste mit etwa sieben oder mehr Optionen. Die anderen wählst du danach, woher die Werte kommen und wie viele es sind:
Checkboxen direkt auf der Seite sind bei kurzen Listen am leichtesten zu überblicken: kein Klick zum Öffnen, jede Option sichtbar. CheckboxGroup aus dem Eintrag Checkbox nimmt ebenfalls options, selectAll und max, und der Eintrag ist kostenlos. Der Tag Input ist für offene Werte gedacht; unser Guide zum React Tag Input behandelt das Aufteilen beim Einfügen und Duplikate. Die Combobox wählt einen einzelnen Wert per Tippen, das passt besser zu einer Stadt oder einem Land.
Hat shadcn einen Multi Select, und wie schlagen sich andere Bibliotheken?
Einen shadcn Multi Select unter diesem Namen gibt es nicht, aber die shadcn Combobox nimmt multiple und rendert Chips mit ComboboxChips. Die Details, Stand Oktober 2026, aus der Doku oder dem Quellcode des jeweiligen Projekts:
Quellen: shadcn/ui Combobox (opens in a new tab), Quellcode von react-select (opens in a new tab), MUI Autocomplete (opens in a new tab), react-multi-select-component (opens in a new tab).
Ein Standardwert von react-select überrascht viele: hideSelectedOptions übernimmt den Wert von isMulti. Gewählte Optionen verschwinden also aus dem Menü, und eine Checkbox-Liste gibt es erst, wenn du die Prop auf false setzt. Das passt zu einem Tag-Feld, in dem man zuerst tippt, und verwirrt Leute, die eine Liste überfliegen.
Läuft deine App schon auf MUI, ist der Autocomplete mit multiple, limitTags und Checkbox-Zeilen die vernünftige Wahl. react-select passt zu einem Multi Select, bei dem Tippen im Vordergrund steht, wenn du mit Emotion-Styling leben kannst, und react-multi-select-component ist ein MIT-Paket, bei dem Alle auswählen standardmäßig an ist. Die shadcn Combobox ist ein guter Start, wenn du nur Chips brauchst. Willst du gemessenen Überlauf, Alle auswählen über Suchergebnisse, ein Maximum und ein Sheet fürs Smartphone schon fertig gebaut, dann deckt unser Multi Select genau das ab.
Womit fängst du am besten an?
Öffne die Doku zum Multi Select. Dort findest du den Playground und Beispiele für Avatare, ein Maximum, Anzeige als Anzahl oder Text, umbrechende Chips, Gruppen mit Alle auswählen und asynchrone Optionen. Multi Select, Tag Input und Combobox gehören zu Wingo UI Pro, $8 im Monat, $80 im Jahr oder $150 einmalig, Stand Oktober 2026 (Preise). Für den Rest des Formulars lies den Guide zu React-Formularkomponenten, und mehr findest du in der Kategorie Komponenten-Guides.
Häufige Fragen
Wie baue ich ein Multi-Select-Dropdown in React?
Halte ein Array der gewählten Werte im State, render einen Button, der eine Listbox mit aria-multiselectable öffnet, und schalte bei jedem Klick auf eine Zeile den Wert um, ohne die Liste zu schließen. Eine React Multi Select Komponente wie der Multi Select von Wingo UI ergänzt Chips mit +N-Überlauf, Suche, Alle auswählen, ein Maximum, asynchrone Optionen und ein Bottom Sheet fürs Smartphone.
Hat shadcn/ui einen Multi Select?
Eine Komponente namens Multi Select gibt es in shadcn/ui Stand Oktober 2026 nicht, aber die Combobox nimmt eine Prop multiple und zeigt die Auswahl als Chips. Die Doku zeigt keine Zeile für Alle auswählen, keinen +N-Überlauf und keinen Drawer fürs Smartphone. Dafür brauchst du eigenen Code oder eine Komponente aus der Community.
Wie zeige ich +N, wenn die Chips eines Multi Select überlaufen?
Miss die Chips in einer versteckten Ebene, nimm sie einzeln dazu, bis der nächste Chip plus der +N-Chip breiter als das Feld wären, und render nur diese, dann einen Chip mit der restlichen Anzahl. Miss mit einem ResizeObserver neu, denn die Breite des Felds und das Laden von Schriften ändern das Ergebnis.
Soll Alle auswählen jede Option wählen oder nur die gefilterten?
Nur die Optionen, die die Person sieht. Wer nach „neu“ sucht und Alle auswählen drückt, erwartet die passenden Zeilen, nicht die 200 versteckten. Der Multi Select von Wingo UI schaltet die sichtbaren Optionen um und stoppt bei maxSelected.
Wie sende ich einen Multi Select mit einem Formular ab?
Render pro Wert ein Hidden Input mit demselben name und lies sie mit formData.getAll(name), oder pack die Komponente in den Controller von react-hook-form und validiere das Array mit zod. Der Multi Select von Wingo UI rendert die Hidden Inputs, wenn du name übergibst.
- Formulare
- Multi Select
- Chips
- Barrierefreiheit
- Mobile UI


