React Action Sheet: wie unter iOS, async und responsive

Ein React Action Sheet ist das, was jemand auf dem Smartphone nach einem Tipp auf ⋯ bei einem Foto, einer Nachricht oder einem Inserat erwartet: Die Seite wird abgedunkelt, eine kurze Liste von Aktionen fährt von unten hoch, Löschen ist rot, und Abbrechen sitzt abgesetzt genau dort, wo der Daumen schon ist. Die meisten Web-Nachbauten des iOS Action Sheets kriegen das Hochfahren hin, und dabei bleibt es. Sie schließen, bevor der Lösch-Request fertig ist, zeigen nichts, wenn er scheitert, bieten keinen Weg per Tastatur und sehen auf einem 1440px-Monitor aus wie ein in die Breite gezogenes Smartphone. Dieser Artikel zeigt, was das Muster braucht, und baut es dann mit dem Action Sheet von Wingo UI, inklusive show() mit await und dem Dialog oder Menü, zu dem es ab 768px wird.
Wann nimmst du ein Action Sheet statt eines Menüs oder Alerts?
Nimm ein Action Sheet, wenn die Person gerade etwas angefangen hat und entscheiden muss, wie es endet, zum Beispiel beim Schließen einer halb geschriebenen E-Mail: Entwurf löschen oder speichern. Genau dieses Beispiel nutzen Apples Richtlinien für Action Sheets (opens in a new tab) (geprüft im Oktober 2026). Sie grenzen das Muster auch von seinen Nachbarn ab: Ein Alert kommt laut Apple meist unerwartet und meldet ein Problem, ein Menü dagegen erwartet man nur, wenn man es selbst aufruft. Dieselbe Seite verlangt drei Dinge, die jede Umsetzung prägen:
- Destruktive Optionen fallen auf. Nutze den destruktiven Stil und setz diese Zeilen nach oben, wo man sie bemerkt.
- Abbrechen kommt nach unten. So kann man eine Aktion ablehnen, die Daten zerstören könnte.
- Kein Scrollen. Für iOS rät Apple davon ab, ein Action Sheet scrollen zu lassen: Je mehr Buttons, desto länger dauert die Wahl, und Scrollen verleitet zu versehentlichen Tipps. Der Abschnitt zu watchOS setzt zusätzlich eine Grenze von vier Buttons inklusive Abbrechen, eine sinnvolle Obergrenze auch auf dem Smartphone.
Im Web wird daraus ein mobiles Aktionsmenü, das ein einzelner Daumen erreicht, und auf dem Desktop etwas Ruhigeres. So teilen sich die vier verwandten Komponenten von Wingo UI die Arbeit:
Was rendert das Action Sheet auf dem Smartphone?
Auf dem Smartphone rendert es ein Bottom Sheet in einem von zwei Stilen. variant="ios" (der Standard) lässt eine Karte mit Titel, Nachricht und 56px hohen, zentrierten Zeilen 8px über dem Home-Indikator schweben, mit Abbrechen in einer eigenen Karte darunter. variant="material" ist ein einziges angedocktes Sheet mit Griff, 48px-Zeilen mit Icons am Anfang und Abbrechen als letzter Zeile. Beide schließt du, indem du sie nach unten ziehst, denn das Sheet fürs Smartphone ist der kostenlose Drawer, der auf vaul aufbaut.
Jede Zeile ist eine ActionSheetAction: { id, label, icon?, description?, tone?, disabled?, onSelect?, keepOpen?, badge? }, wobei tone "neutral", "brand" oder "danger" ist. Hier eine deklarative Action-Sheet-Komponente auf der Karte eines Inserats, mit der destruktiven Zeile zuerst, wie Apple es empfiehlt:
trigger rendert mit asChild, also übergib ein einzelnes Element, das eine Ref annimmt, etwa einen Button. Im iOS-Sheet bleiben Icons verborgen, solange du showIcons nicht setzt; in Material und auf dem Desktop erscheinen sie standardmäßig. Für mehrere Gruppen übergibst du statt actions die Prop groups (ein Array aus Action-Arrays): Unter iOS wird jede Gruppe zu einer eigenen Karte.
$ npx wingo-ui@latest add action-sheetWie geht das Sheet mit async und destruktiven Aktionen um?
Gibt onSelect ein Promise zurück, zeigt die Zeile einen Spinner, die anderen Zeilen werden blasser, und das Sheet weigert sich zu schließen: Escape, ein Tipp auf die abgedunkelte Seite und das Ziehen warten alle, bis das Promise abgeschlossen ist. Wird es erfüllt, feuert onAction(id) und das Sheet schließt. Wird es abgelehnt, wackelt die Zeile wie bei einem falschen Entsperrcode und bleibt für einen neuen Versuch bereit. Das ist der Unterschied zwischen einem Sheet, das wirklich „Gelöscht“ meldet, und einem, das nur so aussieht.
Das Wackeln sagt der Person, dass etwas schiefging, aber nicht was. Deshalb ruft das Beispiel mit dem Inserat toast.error() auf, bevor es den Fehler erneut wirft: Der Toast sagt warum, das Wackeln sagt wo, und die Zeile ist für einen zweiten Tipp bereit. Der Toast braucht einen Toaster, den du einmal in deinem Layout einbindest. Zwei Props ändern das Schließen: closeOnAction={false} hält das Sheet nach jeder Aktion offen, und keepOpen: true auf einer einzelnen Zeile tut dasselbe nur für diese Zeile. Das passt zu einem Schalter wie „Benachrichtigungen stummschalten“.
Wenn du ein Löschen bestätigen willst, ist oft schon das Sheet selbst der richtige Schritt. Ein Titel wie „Dieses Inserat löschen?“, eine Nachricht darunter, eine rote Zeile und Abbrechen ergeben eine Bestätigung mit zwei Tipps, genau dort, wo der Daumen ist. Hat die erste aktive Aktion den Ton danger, setzt das Sheet den Tastaturfokus auf Abbrechen statt auf Löschen. Ein Druck auf Enter direkt nach dem Öffnen zerstört also nie etwas.
Wie wartest du mit show() auf ein Action Sheet?
Ruf useActionSheet().show(options) in einem beliebigen Event-Handler auf und warte mit await auf das Ergebnis: Du bekommst die id der gewählten Aktion zurück oder null. Dafür bindest du vorher einmal ActionSheetProvider weit oben im Baum ein. show() nimmt dieselben Props wie ActionSheet außer open, defaultOpen, onOpenChange und trigger und liefert null, wenn die Person abbricht oder das Sheet schließt. Das Ergebnis kommt erst, nachdem das Promise der gewählten Zeile erfüllt ist, also läuft der Code nach dem await, sobald die Arbeit erledigt ist. Das entspricht Apples Beispiel aus Mail, dem Entwurf, den du schließt:
defaults gilt für jeden Aufruf, die eigenen Optionen des Aufrufs haben aber Vorrang. Dort landen übersetzte Labels oder eine hauseigene variant. Ein zweites show() ersetzt das offene Sheet, und der erste Aufruf liefert null. Schließt das Sheet, geht der Fokus an das Element zurück, das ihn vor dem Aufruf hatte. useActionSheet() wirft außerhalb des Providers einen Fehler, damit ein fehlender Provider in der Entwicklung laut scheitert. Eine abgelehnte Zeile lässt das Promise offen, denn die Person kann es noch einmal versuchen oder abbrechen.
Wie sieht das Action Sheet auf dem Desktop aus?
Smartphones bekommen immer das Sheet; ab 768px wählt die Prop desktop eines von drei Layouts:
desktop="dialog"(der Standard): ein kompakter 400px-Dialog mit denselben Zeilen, linksbündig und mit Icons.desktop="popover": ein Menü, das am Trigger verankert ist. Es zeigt kein Abbrechen, denn Menüs schließen mit Escape und mit Klicks außerhalb. Ein Aufruf vonshow()hat keinen Trigger, an dem es hängen könnte, und fällt deshalb auf den Dialog zurück.desktop="sheet": das Sheet fürs Smartphone in jeder Breite, für Kiosk-Anwendungen oder Oberflächen, die vor allem fürs Tablet gebaut sind.
Framework7 macht etwas Ähnliches: Seine Doku zum Action Sheet (opens in a new tab) nennt eine Option convertToPopover, die das Sheet auf großen Screens in ein Popover verwandelt. Ionics ion-action-sheet (opens in a new tab) (@ionic/react 9.0.8, beide geprüft im Oktober 2026) kennt die Button-Rollen destructive und cancel und rendert den Cancel-Button immer zuletzt. Ein eigenes Layout für breite Screens beschreibt die Doku aber nicht, und present() liefert nichts zurück: Die Auswahl liest du aus dem Ergebnis von onDidDismiss. Sind deine Aktionen eigentlich ein Befehlsmenü mit Checkboxen, Untermenüs und Shortcuts, fang lieber mit dem Dropdown Menu an: Auf dem Desktop ist es ein schwebendes Menü, und unter 768px wird es von selbst zum Action Sheet.
$ npx wingo-ui@latest add dropdown-menuLässt sich das Action Sheet per Tastatur bedienen?
Ja, und zwar nach denselben Regeln wie ein Menü. Beim Öffnen landet der Fokus auf der ersten Aktion, oder auf Abbrechen, wenn die erste Aktion destruktiv ist. Pfeil nach oben und unten wechseln zwischen den Aktionen und Abbrechen, Home und End springen an die Enden, Enter oder Leertaste führen die fokussierte Zeile aus, Tab wandert im Kreis durch das Sheet, und Escape bricht ab. Der Titel benennt das Sheet; fehlt er, wird labels.sheetTitle (standardmäßig „Actions“) zum versteckten Titel für Screenreader, und message wird zur Beschreibung. Ist reduzierte Bewegung eingestellt, wird das Hochfahren des Sheets auf dem Smartphone verkürzt, der Dialog auf dem Desktop blendet nur ein, und gescheiterte Zeilen wackeln nicht.
Welche Stolperfallen zeigen sich auf echten Smartphones?
Vier tauchen auf, sobald das Sheet auf echte Requests und echte Geräte trifft:
- Ein Promise zurückgeben, auf das du nicht warten willst. Jedes Promise aus
onSelecthält das Sheet offen.navigator.share()ist der klassische Fall: Es ist erst abgeschlossen, wenn die Person mit dem nativen Teilen-Dialog fertig ist, und wird abgelehnt, wenn sie es abbricht, was deine Zeile wackeln lässt. Ruf es mitvoidauf oder schließ das Sheet vorher. - Zu viele Zeilen. Jede zusätzliche Zeile muss man lesen, bevor sich der Daumen bewegt. Deshalb verlangt Apple ein Sheet, das nie scrollt. Das Sheet begrenzt seine Liste auf
60dvhund scrollt innerhalb seiner Karte, mit Abbrechen fest darunter, aber eine lange Liste mit Personen oder Ordnern gehört in einen Picker. Unser Guide zum React Bottom Sheet fürs Web behandelt Sheets mit echtem Inhalt. - Der Home-Indikator. Ein Sheet, das an
bottom: 0klebt, legt Abbrechen unter den Home-Balken des iPhones. Die iOS-Karten schweben darüber, und das Material-Sheet polstert mitenv(safe-area-inset-bottom); der Guide zu Safe Area Insets erklärt das CSS. - Das Sheet für endgültige Löschvorgänge nutzen, die eine Erklärung brauchen. „Konto und alle Rechnungen löschen“ verdient einen Alert Dialog: eine zentrierte Karte, bei der ein Tipp auf die abgedunkelte Seite nichts tut, der Fokus auf Abbrechen startet und
await confirm()trueoderfalseliefert.
$ npx wingo-ui@latest add alert-dialogDas Action Sheet ist eines der kleinen Details aus unserer Liste, was eine Web-App ausmacht, die sich nativ anfühlt. Für die ganze mobile Ebene, von Touch-Zielen bis zu Bottom Sheets, lies den Guide zu mobile-first React-Komponenten oder stöbere in Mobile UI in React.
Wie installierst du das Action Sheet?
Führ npx wingo-ui@latest add action-sheet aus. Der Befehl kopiert components/ui/action-sheet.tsx samt Button, Dialog, Drawer, Popover und Spinner, die es importiert, die gemeinsamen Hooks und ihre npm-Pakete (motion, lucide-react, vaul und die Radix-Primitives). Das Action Sheet gehört zu Wingo UI Pro, also melde dich vorher mit npx wingo-ui@latest login an; Drawer und Dropdown Menu, neben denen es steht, sind kostenlos.
Häufige Fragen
Was ist ein Action Sheet in React?
Ein Action Sheet ist eine modale Auswahlliste zu etwas, das die Person gerade getan hat, etwa auf einen Tipp auf den ⋯-Button eines Fotos. Auf dem Smartphone fährt es von unten hoch, zeigt destruktive Optionen in Rot und endet mit einem Abbrechen-Button. In React ist es ein Bottom Sheet mit einer Liste echter Buttons; die Version von Wingo UI baut ihr Sheet fürs Smartphone über den Drawer auf vaul auf.
Was ist der Unterschied zwischen einem Action Sheet und einem Dropdown-Menü?
Ein Dropdown-Menü öffnet man bewusst, um Befehle durchzusehen, und es kann Checkboxen, Radio-Einträge und Untermenüs enthalten. Ein Action Sheet bietet wenige Optionen zu einer einzigen Aktion, mit Titel und Abbrechen. Das Dropdown Menu von Wingo UI wird unter 768px schon von selbst zum Action Sheet. Nimm das Action Sheet, wenn du async Zeilen, Gruppen oder einen Aufruf mit await brauchst.
Soll ich ein Löschen mit einem Action Sheet oder einem Alert Dialog bestätigen?
Laut Apples Richtlinien gehören Optionen zu einer Aktion, die die Person selbst gestartet hat, in ein Action Sheet und nicht in einen Alert; Alerts beschreibt Apple meist als unerwartete Nachricht über ein Problem. Ein Sheet mit einer roten Zeile und Abbrechen reicht für die meisten Löschvorgänge; nimm einen Alert Dialog, wenn sich das Löschen nicht rückgängig machen lässt und einen erklärenden Satz oder eine getippte Bestätigung braucht.
Wie viele Buttons sollte ein Action Sheet haben?
So wenige, dass das Sheet nie scrollt: Apples iOS-Richtlinien raten von einem scrollenden Action Sheet ab, und die Richtlinien für watchOS begrenzen es auf vier Buttons inklusive Abbrechen. Übergibst du mehr Zeilen, begrenzt das Action Sheet von Wingo UI seine Liste auf 60% der dynamischen Viewport-Höhe und scrollt innerhalb seiner Karte, mit Abbrechen fest darunter.
Ist das Action Sheet von Wingo UI kostenlos?
Nein. Action Sheet und Alert Dialog sind Pro-Komponenten. Drawer, Dialog, Popover und Dropdown Menu, auf denen es aufbaut oder neben denen es steht, sind kostenlos.
- Mobile UI
- Action Sheet
- React
- Barrierefreiheit
- iOS


