Dropdown menu
Ein Menü mit Aktionen und Optionen hinter einem Button, mit Gruppen, Untermenüs, Checkbox- und Radio-Einträgen sowie Tastenkürzeln.
pnpm dlx shadcn@latest add https://hextaui.com/r/dropdown-menu.jsonFügt die Komponente, die HextaUI-Theme-Tokens und alle HextaUI-Komponenten hinzu, von denen sie abhängt.
Füge die Theme-Tokens zu deinem globalen CSS hinzu, falls du das noch nicht getan hast.
Installiere die Abhängigkeiten.
pnpm add @base-ui/react @tabler/icons-react class-variance-authority cnKopiere den folgenden Code und füge ihn in dein Projekt ein.
components/ui/dropdown-menu.tsx Passe die Importpfade an dein Projekt-Setup an.
Sicherer Bereich
Eine diagonale Bewegung von einem Untermenü-Trigger zu seinem Untermenü kreuzt benachbarte Trigger. Der sichere Bereich hält das Untermenü offen, während der Zeiger darauf zuhält. Schalte showSafeArea ein, um ihn live zu sehen: Der Punkt wird im Bereich grün und rot dort, wo das Untermenü wechseln würde.
Checkboxen
<DropdownMenuCheckboxItem /> schaltet eine Einstellung um und hält das Menü offen, sodass sich mehrere hintereinander ändern lassen. Der Haken wird ein- und ausgezeichnet, statt aufzupoppen.
Radio group
Umschließe <DropdownMenuRadioItem /> mit einer <DropdownMenuRadioGroup />, um eine Option zu wählen. Ein Label in der Gruppe benennt sie für Screenreader.
Haken rechts
Setze indicator="end" an Checkbox- und Radio-Einträgen, um den Haken nach dem Label zu zeigen, statt einzurücken, was zu Pickern mit einer Beschreibung unter jeder Option passt.
Select-ähnlich
Das Menü ist nie schmaler als sein Trigger. Setze closeOnClick an Radio-Einträgen, wenn das Auswählen einer Option auch das Menü schließen soll.
Zeilenaktionen
Ein Menü bedient jede Zeile. Erstelle ein Handle mit createDropdownMenuHandle, übergib es mit einem payload an jeden Trigger und lies das Payload im Menü. Löschen übergibt an einen Alert Dialog.
Kontrolliert
Übergib open und onOpenChange. Das zweite Argument nennt den Grund der Änderung, etwa Trigger-Druck, Eintrags-Druck oder Escape. Einträge mit closeOnClick={false} halten es offen.
Per Hover öffnen
openOnHover am Trigger öffnet das Menü nach delay und schließt es nach closeDelay. Klicken und die Tastatur funktionieren weiterhin, sodass Touch- und Tastaturnutzer nicht ausgesperrt werden.
Deaktiviert
Ein deaktivierter Trigger öffnet sich nie. Deaktivierte Einträge bleiben sichtbar und werden von den Pfeiltasten übersprungen.
Langer Inhalt
Labels werden umgebrochen, statt das Menü über 20 rem zu dehnen, Strings ohne Umbruchstelle brechen überall, und Kürzel bleiben in der ersten Zeile.
Scrollen
Wenn nicht für jeden Eintrag Platz ist, scrollt das Menü im Viewport, und der hervorgehobene Eintrag scrollt in den Sichtbereich.
In einem Sheet
Das Menü liegt über dem Sheet. Escape schließt zuerst das Menü, dann das Sheet.
Rechts nach links
Menü, Untermenü-Chevron und Untermenü-Seite folgen der Richtung des Triggers. Kürzel behalten ihre Links-nach-rechts-Reihenfolge.
| Taste | Aktion |
|---|---|
| EnterSpace↓ | Am Trigger: öffnet das Menü und hebt den ersten Eintrag hervor. |
| ↓ | Hebt den nächsten Eintrag hervor, am Ende wird umgebrochen. |
| ↑ | Hebt den vorherigen Eintrag hervor, am Anfang wird umgebrochen. |
| Home | Hebt den ersten Eintrag hervor. |
| End | Hebt den letzten Eintrag hervor. |
| EnterSpace | Führt den hervorgehobenen Eintrag aus. Checkbox- und Radio-Einträge schalten um und halten das Menü offen. |
| → | Öffnet das hervorgehobene Untermenü und wechselt hinein. ← in Rechts-nach-links-Layouts. |
| ← | Schließt das aktuelle Untermenü und kehrt zu seinem Trigger zurück. → in Rechts-nach-links-Layouts. |
| Esc | Schließt das aktuelle Menü und gibt den Fokus an seinen Trigger zurück. In einem Untermenü schließt sich nur dieses Untermenü. |
| A–Z | Hebt den nächsten Eintrag hervor, der mit diesem Buchstaben beginnt. |
- Der Trigger wird als Menü-Button angesagt, und der Fokus kehrt zu ihm zurück, wenn das Menü schließt.
- Gib reinen Icon-Triggern ein
aria-label, wie es das Beispiel mit den Zeilenaktionen tut. <DropdownMenuShortcut />ist nur ein visuelles Label. Binde die Tasten selbst.- Bei reduzierter Bewegung blendet das Menü ohne Skalierung ein und aus, und das Blinken der Einträge entfällt.
Basiert auf dem Base UI Menu. Jeder Teil akzeptiert die Props der Primitive, die er umschließt.
| Prop | Typ | Standard |
|---|---|---|
open | boolean | – |
defaultOpen | boolean | false |
showSafeAreaZeichnet den sicheren Bereich des Untermenüs, solange das Menü geöffnet ist. Zum Debuggen und für Demos. | boolean | false |
onOpenChangedetails.reason gibt an, was die Änderung ausgelöst hat. | (open: boolean, details) => void | – |
modalSperrt das Scrollen der Seite und blockiert Klicks nach außen, solange geöffnet. | boolean | true |
loopFocusDie Pfeiltasten an beiden Enden umbrechen. | boolean | true |
handleVerbindet losgelöste Trigger mit diesem Menü. | DropdownMenuHandle<Payload> | – |
childrenVerwende die Funktionsform, um das Payload des öffnenden Triggers zu lesen. | ReactNode | ({ payload }) => ReactNode | – |
disabled | boolean | false |
| Prop | Typ | Standard |
|---|---|---|
openOnHover | boolean | false |
delayMillisekunden, bevor ein Hover das Menü öffnet. | number | 100 |
closeDelayMillisekunden, bevor sich ein per Hover geöffnetes Menü schließt. | number | 0 |
handle | DropdownMenuHandle<Payload> | – |
payloadWird an das Menü übergeben, wenn dieser Trigger es öffnet. | Payload | – |
disabled | boolean | false |
render | ReactElement | (props, state) => ReactElement | <button> |
| Attribut | Beschreibung |
|---|---|
data-slot="dropdown-menu-trigger" | Den Trigger in CSS ansprechen. |
data-popup-open | Vorhanden, solange das Menü geöffnet ist. |
data-pressed | Vorhanden, solange der Trigger gedrückt ist. |
data-disabled | Vorhanden, wenn der Trigger deaktiviert ist. |
| Prop | Typ | Standard |
|---|---|---|
side | "top" | "bottom" | "left" | "right" | "inline-start" | "inline-end" | "bottom" |
align | "start" | "center" | "end" | "start" |
sideOffset | number | 4 |
alignOffset | number | 0 |
collisionPaddingAbstand zwischen dem Menü und dem Rand des Viewports. | number | Rect | 8 |
anchorAn einem anderen Element statt am Trigger positionieren. | Element | RefObject | VirtualElement | – |
sticky | boolean | false |
render | ReactElement | (props, state) => ReactElement | <div> |
| Attribut | Beschreibung |
|---|---|
data-slot="dropdown-menu-content" | Das Menü in CSS ansprechen. |
data-open | Vorhanden, solange das Menü geöffnet ist. |
data-starting-style | Vorhanden, während das Menü eingeblendet wird. |
data-ending-style | Vorhanden, während das Menü ausgeblendet wird. |
data-side | Die Seite, auf der sich das Menü nach der Kollisionsbehandlung eingestellt hat. |
data-align | Die Ausrichtung, auf die es sich eingestellt hat. |
data-chosen | Vorhanden, nachdem ein Eintrag geklickt wurde, sodass das Menü vor dem Schließen auf das Bestätigungsblinken des Eintrags wartet. |
--anchor-width | Die Breite des Triggers. Das Menü ist mindestens so breit. |
--available-height | Verbleibender Platz im Viewport. Lange Menüs scrollen darin. |
--transform-origin | Der Punkt neben dem Trigger, von dem aus die Skalierungsanimation wächst. |
| Prop | Typ | Standard |
|---|---|---|
variant | "default" | "destructive" | "default" |
insetRückt den Eintrag ein, damit er mit Checkbox-Einträgen fluchtet. | boolean | false |
closeOnClick | boolean | true |
onClick | (event) => void | – |
labelText für die Typeahead-Suche, wenn die Kinder kein reiner Text sind. | string | – |
disabled | boolean | false |
renderRendere einen Link mit render={<a href="…" />}. | ReactElement | (props, state) => ReactElement | <div> |
| Attribut | Beschreibung |
|---|---|
data-slot="dropdown-menu-item" | Items in CSS ansprechen. |
data-variant | Die aktuelle Variante. |
data-highlighted | Vorhanden, solange der Eintrag per Zeiger oder Tastatur hervorgehoben ist. |
data-disabled | Vorhanden, wenn das Item deaktiviert ist. |
data-chosen | Vorhanden am gerade geklickten Eintrag, solange er blinkt. |
data-inset | Vorhanden, wenn inset gesetzt ist. |
| Prop | Typ | Standard |
|---|---|---|
checked | boolean | – |
defaultChecked | boolean | false |
onCheckedChange | (checked: boolean, details) => void | – |
closeOnClick | boolean | false |
inset | boolean | false |
indicator | "start" | "end" | "start" |
disabled | boolean | false |
| Attribut | Beschreibung |
|---|---|
data-slot="dropdown-menu-checkbox-item" | Checkbox-Einträge in CSS ansprechen. |
data-checked | Vorhanden, wenn aktiviert. |
data-unchecked | Vorhanden, wenn nicht aktiviert. |
data-highlighted | Vorhanden, solange der Eintrag per Zeiger oder Tastatur hervorgehoben ist. |
data-disabled | Vorhanden, wenn das Item deaktiviert ist. |
data-chosen | Vorhanden am gerade geklickten Eintrag, solange er blinkt. |
data-inset | Vorhanden, wenn inset gesetzt ist. |
| Prop | Typ | Standard |
|---|---|---|
value | Value | – |
defaultValue | Value | – |
onValueChange | (value: Value, details) => void | – |
disabled | boolean | false |
| Prop | Typ | Standard |
|---|---|---|
value | Value | – |
closeOnClick | boolean | false |
inset | boolean | false |
indicator | "start" | "end" | "start" |
disabled | boolean | false |
| Attribut | Beschreibung |
|---|---|
data-slot="dropdown-menu-radio-item" | Radio-Einträge in CSS ansprechen. |
data-checked | Vorhanden am ausgewählten Eintrag. |
data-unchecked | Vorhanden an den anderen Einträgen. |
data-highlighted | Vorhanden, solange der Eintrag per Zeiger oder Tastatur hervorgehoben ist. |
data-disabled | Vorhanden, wenn das Item deaktiviert ist. |
data-chosen | Vorhanden am gerade geklickten Eintrag, solange er blinkt. |
data-inset | Vorhanden, wenn inset gesetzt ist. |
Gruppiert zusammengehörige Einträge. Ein <DropdownMenuLabel /> darin wird zum zugänglichen Namen der Gruppe.
| Prop | Typ | Standard |
|---|---|---|
inset | boolean | false |
render | ReactElement | (props, state) => ReactElement | <div> |
Eine Trennlinie zwischen Gruppen, als Separator angesagt.
| Prop | Typ | Standard |
|---|---|---|
dirKürzel behalten ihre Tastenreihenfolge in Rechts-nach-links-Menüs. | "ltr" | "rtl" | "ltr" |
| Prop | Typ | Standard |
|---|---|---|
open | boolean | – |
defaultOpen | boolean | false |
onOpenChange | (open: boolean, details) => void | – |
closeParentOnEscBei Escape das ganze Menü schließen, nicht nur dieses Untermenü. | boolean | false |
| Prop | Typ | Standard |
|---|---|---|
inset | boolean | false |
disabled | boolean | false |
delayMillisekunden, bevor das Hovern das Untermenü öffnet. | number | 100 |
closeDelay | number | 0 |
| Attribut | Beschreibung |
|---|---|
data-slot="dropdown-menu-sub-trigger" | Untermenü-Trigger in CSS ansprechen. |
data-popup-open | Vorhanden, solange sein Untermenü geöffnet ist. |
data-highlighted | Vorhanden, solange hervorgehoben. |
| Prop | Typ | Standard |
|---|---|---|
sideOffset | number | 0 |
alignOffset | number | -4 |
render | ReactElement | (props, state) => ReactElement | <div> |
| Attribut | Beschreibung |
|---|---|
data-slot="dropdown-menu-sub-content" | Untermenüs in CSS ansprechen. |
data-open | Vorhanden, solange das Menü geöffnet ist. |
data-starting-style | Vorhanden, während das Menü eingeblendet wird. |
data-ending-style | Vorhanden, während das Menü ausgeblendet wird. |
data-side | Die Seite, auf der sich das Menü nach der Kollisionsbehandlung eingestellt hat. |
data-align | Die Ausrichtung, auf die es sich eingestellt hat. |
data-chosen | Vorhanden, nachdem ein Eintrag geklickt wurde, sodass das Menü vor dem Schließen auf das Bestätigungsblinken des Eintrags wartet. |
--available-height | Verbleibender Platz im Viewport. Lange Menüs scrollen darin. |
--transform-origin | Der Punkt neben dem Trigger, von dem aus die Skalierungsanimation wächst. |
- Alert dialogEin Bestätigungsdialog für destruktive oder wichtige Aktionen, der auf asynchrone Arbeit wartet und auf Smartphones zum Bottom Sheet wird.
- CommandEine durchsuchbare Liste von Aktionen, inline oder als ⌘K-Palette, mit Seiten, Tastenkürzeln und hervorgehobenen Treffern.
- Context menuEin Menü mit Aktionen per Rechtsklick oder langem Drücken, mit Untermenüs, Checkbox- und Radio-Einträgen sowie Halte-Feedback auf Touch-Geräten.
- DialogEin Fenster über der Seite für Formulare und fokussierte Aufgaben, mit fixiertem Header und Footer, Verschachtelung und einem wischbaren Bottom Sheet auf Smartphones.
- DrawerEin Panel, das von jeder Kante hereingleitet und deinem Finger folgt, mit Snap-Punkten, einem funktionierenden Griff und verschachtelten Drawern, die sich stapeln.
- Hover cardEine Vorschaukarte, die sich öffnet, wenn ein Link mit der Maus berührt oder fokussiert wird, für Inhalte, die sehende Nutzer kurz überfliegen können.
In Blocks verwendet
Blocks, die auf Dropdown menu aufbauen.
- Prompt InputEin Chat-Composer, der als ruhige einzelne Zeile beginnt, beim Schreiben zu einer Karte wächst und nach unten wandert, sobald die Unterhaltung beginnt. Enter sendet, sicher bei japanischer und chinesischer Eingabe. Dateien per Einfügen, Ablegen oder Auswählen hinzufügen, mit Vorschau, Fortschritt und Wiederholen. @ fügt Dateien hinzu und / führt Befehle aus einem Menü an der Einfügemarke aus. Ein Modellwähler mit Zifferntasten, ein Effort-Slider, der bei Max lebendig wird, ein Kontextring, Diktat mit Live-Wellenform, Tool-Chips, eine Warteschlange für Nachrichten, die während einer streamenden Antwort getippt werden, und Entwürfe, die einen Reload überstehen.
- API keysDie API-Schlüssel-Seite eines KI-Produkts, wie in den Konsolen von OpenAI und Anthropic. Schlüssel mit eingeschränkten Berechtigungen und Ablaufdatum erstellen, das Secret einmal sehen mit einem Kopieren, das sich bestätigt, mit Rückgängig widerrufen, direkt umbenennen, mit Übergangsfrist rotieren und die Nutzung pro Schlüssel sehen.
- ArtifactDas Panel neben einem KI-Chat, das zeigt, was das Modell erzeugt hat. Webseiten, SVGs, Dokumente und Code streamen live ein und wechseln dann zu einer Sandbox-Vorschau, mit Versionen zum Vergleichen und Wiederherstellen, einem anpassbaren Split und einem Bottom Sheet auf Smartphones.
- Chat SidebarDie Seitenleiste für eine Chat-App. Logo, Suche und Neuer Chat oben, deine eigenen Links darunter, angeheftete Chats, Projekte, die sich aufklappen und ihre Chats zeigen, zuletzt verwendete nach Tag gruppiert und Zeilen mit Hover- und Rechtsklick-Menüs, direktem Umbenennen, Löschen mit Rückgängig und Live-Antwortzuständen.