React Segmented Control: iOS-Thumb, Drag, wann es passt

Ein React Segmented Control ist die Reihe aus zwei bis fünf Optionen mit einem erhabenen Thumb unter der ausgewählten, das Control, mit dem du in der Health-App auf iOS den Zeitraum der Diagramme wählst. Wer nach einem iOS Segmented Control Web-Component sucht, findet vor allem Pakete für React Native, und shadcn/ui liefert im Oktober 2026 keins. Dieser Guide zeigt, was die Web-Version richtig machen muss (Thumb, Touch, Tastatur und Radio-Semantik), und dann die wichtigere Entscheidung: wann Tabs, eine Toggle Group oder Radio Cards das bessere Control sind. Die Beispiele nutzen das kostenlose Segmented Control von Wingo UI, der Bibliothek, die wir bauen. Wir sind also nicht neutral; Fakten von außen verlinken auf ihre Quellen.
Was ist ein Segmented Control im Web?
Eine Radio-Gruppe mit anderem Aussehen. Jedes Segment ist eine Option, genau eine ist ausgewählt, und die Auswahl gilt sofort, ohne Absende-Button. Apples Human Interface Guidelines (opens in a new tab) beschreiben es als Weg, eng verwandte Optionen anzubieten, die ein Objekt, einen Zustand oder eine Ansicht beeinflussen. Material Design 3 hat einen nahen Verwandten, den Segmented Button (opens in a new tab). Deshalb wird das Control auch als React Segmented Button gesucht.
Damit ist die Umsetzung klar: Das Markup ist eine radiogroup mit radio-Items, das WAI-ARIA Radio Group Pattern (opens in a new tab) legt die Tastatur fest, und ein name sorgt dafür, dass es wie native Radios abgeschickt wird. Thumb, Spring-Animation und Drag kommen obendrauf.
Wie fügst du ein Segmented Control in React ein?
Installier es, übergib options und lass es seinen Wert selbst verwalten oder steuere ihn von außen:
Jede Option nimmt value, label und optional icon, badge (eine Zahl zeigt einen Zähler, der bei 0 verschwindet), tooltip und disabled. Die Props für das Aussehen sind size (sm, md oder lg, eine Leiste von 32, 40 oder 48px), radius, tone (Standard neutral, ein weißer Thumb wie auf iOS, der im Dark Mode zu einem angehobenen Grau wird) oder eine beliebige CSS-color, und dividers, die feinen Linien zwischen nicht ausgewählten Segmenten. Lässt du defaultValue weg, startet es auf der ersten aktivierten Option.
$ npx wingo-ui@latest add segmented-controlFalls du ein React Segmented Control Tailwind-Rezept suchst: Das ganze Aussehen besteht aus Tailwind-v4-Utilities auf Design Tokens, und jeder innere Teil nimmt Klassen über classNames (item, thumb, icon, label, badge, divider). App-weite Standardwerte laufen über den kostenlosen UIProvider: <UIProvider defaults={{ "segmented-control": { radius: "full" } }}> macht jedes Segmented Control in der App komplett rund.
Warum fühlt es sich wie das iOS-Control an?
Drei Details: Der Thumb bewegt sich mit Spring-Physik statt mit einem linearen Tween, er folgt dem Finger, und er blockiert nie das Scrollen.
Der Thumb animiert nur transform. Er wird im ausgewählten Segment gerendert, also gibt ihm CSS im Ruhezustand die Größe. Ändert sich der Wert, misst er die Box, die er verlässt, springt per transform dorthin und federt mit der snappy-Spring aus lib/motion (stiffness 500, damping 32) zurück auf null Versatz. left und width zu animieren würde in jedem Frame das Layout neu berechnen; ein transform bleibt auf dem Compositor. Sein Eckenradius wird durch die aktuelle Skalierung geteilt, damit behält ein Thumb, der sich zwischen einem kurzen und einem langen Label streckt, runde Ecken. Eine Änderung mitten in der Bewegung startet dort, wo der Thumb gerade auf dem Screen ist, und behält seine Geschwindigkeit.
Er reagiert auf den Finger. Drückst du auf den Thumb, schrumpft er auf 96%. Hältst du weiter und schiebst seitwärts, folgt der Wert dem Segment unter deinem Finger und bleibt dort, wo du loslässt. Die feinen Linien neben dem Thumb blenden aus, wie auf iOS.
Ein vertikaler Swipe scrollt weiter die Seite. Die Leiste setzt touch-action: pan-y, damit der Browser das vertikale Scrollen behält, und der Code wartet 8px Bewegung ab, bevor er entscheidet, was die Geste ist. Diesen Teil solltest du übernehmen, wenn du ein eigenes baust. Gekürzt aus der Komponente:
touch-action: none auf der Leiste würde den Drag einfacher machen und jeden festhalten, der auf dem Control zu scrollen beginnt. Nach einem Drag landet der folgende Klick auf dem Segment, wo der Drag begann. Die Komponente verschluckt ihn deshalb, sonst springt der Wert zurück.
Ist „Bewegung reduzieren“ aktiv, springt der Thumb direkt an seinen neuen Platz, und das Schrumpfen beim Drücken ist aus.
Ist ein Segmented Control barrierefrei?
Ja, wenn die Semantik eine Radio-Gruppe ist, und die bekommst du von Radix fast geschenkt. Das Segmented Control baut auf @radix-ui/react-radio-group auf: Die Leiste ist eine radiogroup, jedes Segment ein radio mit aria-checked, und das ganze Control ist ein einziger Tab-Stopp. Links und Rechts (auch Hoch und Runter) bewegen den Fokus und wählen aus, passend zur APG-Regel für eine Radio-Gruppe außerhalb einer Toolbar. Wir haben Pos1 und Ende ergänzt, deaktivierte Segmente werden übersprungen, und loop={false} stoppt die Pfeile an den Enden. Mantine geht denselben Weg: Laut der SegmentedControl-Doku (opens in a new tab) (v9.7.1, Oktober 2026) arbeiten darunter Radio-Inputs.
Vier Dinge liegen bei dir:
- Ein Name. Übergib
aria-labeloderaria-labelledby, das auf eine sichtbare Überschrift zeigt; beide landen auf der radiogroup. - Text für Icons. Gib Icon-Optionen trotzdem ein
label. MiticonOnlywird es zumaria-labeldes Segments und zu seinem Tooltip, der beim Hover, beim Tastaturfokus und bei langem Druck auf Touchscreens erscheint. - Ein Formularname. Übergib
name, dann wird der ausgewählte Wert in einem<form>wie bei nativen Radios mitgeschickt. - Ein Weg ohne Drag. WCAG 2.5.7 Dragging Movements (opens in a new tab) (Stufe AA) verlangt, dass alles, was per Drag geht, auch mit einem einzelnen Zeiger ohne Ziehen funktioniert. Das Tippen auf ein Segment ist dieser Weg, also behalte es. Mach den Drag nie zum einzigen Weg.
Eine Falle, wenn du selbst auf Radix baust: Radix wählt das nächste Radio nur aus, wenn die Pfeiltaste noch gedrückt ist, sobald der verzögerte Fokus ankommt. Ein sehr schneller Druck (ein Screenreader, eine Fernbedienung, Automatisierung) kann also den Fokus bewegen, ohne etwas auszuwählen. Die Komponente wählt bei jedem Fokus aus, der auf eine Pfeiltaste folgt, so ändert auch ein schneller Druck den Wert.
Wie sollte sich ein Segmented Control auf dem Smartphone verhalten?
Es sollte auf Touch 44px hoch sein, die Breite teilen und beim Tippen nie grau aufblitzen. Die Größe md ist mit Maus eine Leiste von 40px und wächst auf Geräten mit grobem Zeiger auf 44px (pointer-coarse:h-11). Die Größe sm behält ihren 32px-Look und bekommt eine unsichtbare Trefferfläche, die 44px erreicht; lg ist überall 48px. Warum 44px, und welche Tailwind-Varianten das nur auf Touch anwenden, steht im Guide zur minimalen Touch-Target-Größe in React und Tailwind.
fullWidth gibt jedem Segment einen gleichen Anteil am Container, das übliche Layout unter einem Header auf dem Smartphone. Ein Segment mit langem Label behält seine natürliche Breite, statt abgeschnitten zu werden, und die anderen teilen sich den Rest. Jedes Segment trägt touch-manipulation und eine transparente -webkit-tap-highlight-color. Ein schneller zweiter Tipp zoomt also nie die Seite, und iOS zeigt kein graues Aufblitzen. Setz dir="rtl", dann spiegeln sich Layout, Pfeiltasten und Drag.
Die übrigen Regeln (Sheets statt Popover, Safe Areas, Alternativen zu Hover) stehen im Pillar-Artikel zu Mobile-first React-Komponenten, und die Kategorie Mobile UI in React sammelt jeden Guide zum Thema.
Segmented Control, Tabs, Toggle Group oder Radio Cards: Was passt wann?
Entscheide danach, was die Auswahl ändert. Das Aussehen sagt wenig, denn die Tabs von Wingo UI haben eine segmented-Variante mit demselben erhabenen Thumb. Der Unterschied liegt in der Semantik und damit darin, was eine Person mit Screenreader als Nächstes erwartet.
Apple zieht auf iOS eine ähnliche Grenze: Für den Wechsel zwischen völlig getrennten Bereichen einer App empfehlen die Richtlinien (opens in a new tab) stattdessen eine Tab Bar. Hier dieselben Segmente als Tabs, jedes mit eigenem Panel:
$ npx wingo-ui@latest add tabsDie Toggle Group braucht noch eine Anmerkung. Im Single-Modus rendert Radix sie ebenfalls als radiogroup, aber ihre Pfeiltasten bewegen nur den Fokus, und Leertaste oder Enter betätigen das Item. Das ist die APG-Regel für eine Radio-Gruppe in einer Toolbar: Dort bleibt der ausgewählte Button gleich, während du mit den Pfeilen durchgehst. Ein Schalter für die Ausrichtung in einer Editor-Toolbar ist also eine Toggle Group im Single-Modus, ein eigenständiger Zeitraum ein Segmented Control. Wenn mehrere an sein können, passt von den vieren nur die Toggle Group im Modus multiple:
$ npx wingo-ui@latest add toggle-groupRadio Cards sind besser, wenn sich die Optionen nicht selbst erklären. „Kurier, Packstation, Abholung“ passt in ein Segmented Control; „Lieferung nach Hause, FedEx, 1-2 Tage, $9.99“ nicht, und wer das in ein Segment quetscht, versteckt den Preis, der die Wahl entscheidet. Der Guide zu React-Formularkomponenten behandelt die breitere Wahl zwischen Radio Group, Select und Combobox in einem Formular.
Was geht bei Segmented Controls schief?
Vier Dinge: zu viele Segmente, Icons gemischt mit Text, ein Wert außerhalb der Optionen und ein fehlender Name.
- Zu viele Segmente. Apple nennt auf dem iPhone höchstens etwa fünf Segmente, und laut der SegmentedButton-Doku von Flutter (opens in a new tab) kommen sie typischerweise zum Einsatz, wenn es nur 2 bis 5 Optionen gibt. Sechs oder mehr Labels auf einem 360px-Screen werden eng oder abgeschnitten; nimm dann ein Select oder scrollende Tabs.
- Icons und Text gemischt. Apples Richtlinien bevorzugen in einem Control das eine oder das andere. Nimm Text oder
iconOnlymit Labels als Namen. - Ein gesteuerter Wert, der nicht in
optionssteht. Das Control zeigt dann keinen Thumb, was kaputt aussieht. Meist passiert das, wenn die Optionen nach dem Wert laden. - Kein Name. Eine radiogroup ohne
aria-labelwird als unbenannte Gruppe von Radios vorgelesen.
Wie sieht ein komplettes Beispiel aus?
Eine Bestellübersicht, die eine Liste nach Status filtert. Die Auswahl ändert den Inhalt auf dem Screen, und es gibt vier kurze Optionen, also ist das ein Fall für das Segmented Control. Die Anzahl steht in Badges, und eine Statuszeile sagt Screenreadern, wie viele Bestellungen sichtbar sind:
In einem Formular lässt du den State weg und gibst ihm einen name. Eine Server Action liest ihn dann wie jedes Radio:
Womit fängst du an?
Installier das kostenlose Control und setz es dort ein, wo heute ein Zeitraum, ein Ansichtswechsel oder ein Einheitenschalter sitzt:
Tabs und Radio Group sind ebenfalls kostenlos. Toggle Group und Nav Tabs aus der Tabelle oben gehören zu Wingo UI Pro. Wenn jede Option eine ganze Seite ist, zwischen denen man wischt, passen React Swipeable Tabs besser.
Häufige Fragen
Hat shadcn/ui ein Segmented Control?
Nicht im Oktober 2026. Die Komponentenliste hat Tabs, Toggle Group, Radio Group und Button Group. Wer eins auf shadcn/ui baut, stylt also eine davon um. Wähl die Basis danach, was die Auswahl tut: Tabs für Panels, eine Radio-Gruppe für einen Wert.
Was ist der Unterschied zwischen einem Segmented Control und Tabs?
Tabs zeigen ein anderes Panel und liefern die Rollen tablist, tab und tabpanel, verknüpft über aria-controls. Ein Segmented Control wählt einen Wert, der den Inhalt auf dem Screen ändert, etwa einen Zeitraum, und ist eine radiogroup. Für den Wechsel zwischen getrennten Bereichen einer App empfehlen Apples Richtlinien eine Tab Bar.
Wie viele Optionen sollte ein Segmented Control haben?
Zwei bis fünf. Apples Human Interface Guidelines nennen auf dem iPhone höchstens etwa fünf Segmente, und die Doku zum SegmentedButton von Flutter (Material) sagt, dass Segmented Buttons typischerweise bei 2 bis 5 Optionen eingesetzt werden. Ab sechs nimm ein Select oder eine scrollende Reihe Tabs.
Ist ein Segmented Control für Screenreader zugänglich?
Ja, wenn es als radiogroup aus Radio-Items mit einem Namen gebaut ist: ein Tab-Stopp, Pfeiltasten, die bewegen und auswählen, und aria-checked auf dem ausgewählten Segment. Segmente nur mit Icon brauchen zusätzlich einen Textnamen, den der iconOnly-Modus von Wingo UI aus dem label jeder Option nimmt.
Kann ein Segmented Control mit einem Formular abgeschickt werden?
Ja. Gib dem Segmented Control von Wingo UI einen name, dann schickt es in einem Formular den ausgewählten Wert wie eine Radio-Gruppe mit, und FormData und Server Actions lesen ihn mit formData.get.
Ist das Segmented Control von Wingo UI kostenlos?
Ja. Segmented Control, Tabs, Radio Group und Select sind kostenlos und lassen sich mit npx wingo-ui@latest add installieren. Toggle Group und Nav Tabs gehören zu Wingo UI Pro.
- Mobile UI
- React
- Barrierefreiheit
- Tailwind CSS
- iOS


