{
 "$schema": "../../schema.json",
 "schema": "fundus/1",
 "id": "button-gruppe-expressiv",
 "name": "Button-Gruppe expressiv (Toggle, Auswahl, Split)",
 "name_en": "Expressive button groups: connected toggle group, single select and split button (Material 3 Expressive principle)",
 "kurz": "Verbundene Knopfgruppe nach Material 3 Expressive: Druck macht breiter und eckiger, Auswahl macht rund, der Split-Button öffnet sein Menü mit drehendem Pfeil.",
 "kategorie": "Buttons",
 "kategorie_slug": "buttons",
 "kategorie_nr": 18,
 "bau_chat": "B",
 "prioritaet": "B",
 "trendstatus": "aufsteigend",
 "belegstatus": "quellenbelegt",
 "website_belege": 0,
 "stimmung": [
  "präzise",
  "verspielt"
 ],
 "stimmung_roh": [
  "verspielt",
  "präzise",
  "produkt"
 ],
 "technik": [
  "css",
  "vanilla-js",
  "popover",
  "aria"
 ],
 "technik_gruppen": [
  "css",
  "js",
  "andere"
 ],
 "leistungskosten": "niedrig",
 "steckbrief": {
  "beschreibung": "Mehrere Knöpfe bilden eine Einheit und reagieren aufeinander. In der verbundenen Gruppe liegen die Knöpfe 2 px auseinander, außen ganz rund, innen mit kleinen Ecken. Wer drückt, macht seinen Knopf breiter und eckiger, die Nachbarn geben nach. Wer auswählt, macht ihn ganz rund und farbig, ein Häkchen kommt dazu. Drei Rollen: Toggle-Gruppe mit Mehrfachauswahl (aria-pressed), Einfachauswahl als Radiogruppe und Split-Button aus Hauptaktion und Menü-Knopf. Beim Split-Button dreht sich der Pfeil, und der Menü-Knopf wird beim Öffnen ganz rund. Das Prinzip stammt aus Material 3 Expressive (2025) und wird hier mit CSS und wenig JS nachgebaut.",
  "warum_es_wirkt": "Die Form selbst zeigt den Zustand: rund heißt gewählt, eckig heißt gerade gedrückt. Das ist neben Farbe und Häkchen ein drittes Signal und macht die Auswahl auch ohne Farbsehen klar. Die Breitenänderung beim Druck gibt sofort spürbare Rückmeldung, ohne Ripple oder Wackeln. Der Split-Button hält die häufigste Handlung mit einem Klick erreichbar und versteckt Varianten der Handlung, statt drei Knöpfe nebeneinander zu stellen.",
  "wann_einsetzen": "Filter mit wenigen Eigenschaften über einer Ergebnisliste (Shop, Kursplan, Rezepte). Sortierung oder Ansicht (Raster oder Liste). Antwortwahl in Kursen und Quiz. Split-Button in der Kaufbox oder bei Produkt-UI, wenn eine Hauptaktion klare Nebenformen hat (In den Korb, als Geschenk, merken).",
  "wann_nicht": "Mehr als fünf Optionen (dann Auswahlliste oder Filter-Schublade). Navigation zwischen Seiten (dann Links in einem nav). Größenwahl in der Kaufbox bleibt eine echte Radiogruppe ohne Breitenwechsel. Ruhige Rezepte (Luxus, Kanzlei, Praxis): ohne Breitenwechsel, nur Farbe und Ecken. Split-Button nicht, wenn die Nebenaktionen gleich wichtig sind wie die Hauptaktion, und nie mit einer gefährlichen Aktion im Menü ohne Rückfrage.",
  "varianten": [
   "Toggle: verbundene Gruppe mit Mehrfachauswahl, aria-pressed, Auswahl morpht die Ecken",
   "Einzeln: Einfachauswahl als Radiogruppe (role=radiogroup, aria-checked), Pfeile wählen",
   "Split: Hauptaktion plus Menü-Knopf mit Popover-Menü, Pfeil dreht sich, Knopf wird rund",
   "Standard-Gruppe mit 12 px Abstand statt verbunden (jeder Knopf behält seine Form)",
   "FAB-Menü auf dem Telefon (siehe mobile-bottom-navigation)"
  ],
  "umsetzung": "Verbundene Gruppe: display:flex, gap 2px, Knöpfe flex:1 1 0. min-width bleibt auto, damit lange Beschriftungen bei größeren Textabständen nicht abgeschnitten werden; erst unter 480 px min-width:0 mit Auslassung. Ecken über zwei Variablen (links, rechts): innen 8px, außen Hälfte der Höhe in px (nicht 999px, sonst springt die Animation). Druck: Klasse .drueckt bei pointerdown bzw. Leertaste/Enter, mindestens 150 ms, setzt flex-grow 1.2 und innere Ecken 4px. Auswahl: alle Ecken rund, Markengrün, Häkchen fährt über grid-template-columns ein. Toggle: role=toolbar mit Namen, aria-pressed, roving tabindex (Pfeile, Pos1, Ende). Einfachauswahl: role=radiogroup, role=radio, aria-checked, nur der gewählte Knopf hat tabindex=0, Pfeile wählen mit Umlauf. Split: zwei buttons in role=group; Menü-Knopf mit aria-haspopup=menu, aria-expanded, aria-controls, aria-label; Menü als popover mit role=menu, menuitem und menuitemcheckbox, Lage per JS (beforetoggle) unter dem Knopf. Enter, Leertaste und Pfeil runter öffnen und fokussieren den ersten Eintrag, Pfeil hoch den letzten; im Menü Pfeile mit Umlauf, Pos1, Ende, Anfangsbuchstabe, Escape schließt und gibt den Fokus zurück, Tab schließt. Light-Dismiss schließt schon beim pointerdown, deshalb den Offen-Zustand vor dem Klick merken. Ohne Popover-Unterstützung: Attribut entfernen und Klasse .offen. Hauptaktion: Laden (Kreisel, „Wird hinzugefügt …“), Erfolg („Liegt im Korb“, Grün), Ansage per role=status. Nicht lieferbar: aria-disabled mit lesbarem Text und gestrichelter Kante, Menü bleibt bedienbar (Benachrichtigen).",
  "mobil": "Gruppe nimmt die volle Breite, Beschriftungen kurz halten (höchstens vier Optionen auf 320 px). Trefferfläche mindestens 44 px hoch. Kein Hover; Druck zeigt sich über :active. Menü des Split-Buttons öffnet unter dem Knopf und bleibt im Viewport.",
  "reduzierte_bewegung": "Kein Breitenwechsel, Ecken und Farbe wechseln ohne Übergang, Menü erscheint ohne Gleiten, Pfeil springt. Umordnen ohne FLIP.",
  "barrierefreiheit": "Echte button-Elemente. Toggle: aria-pressed, Gruppe role=toolbar oder group mit Namen. Einfachauswahl: role=radiogroup mit Namen, role=radio, aria-checked, roving tabindex (WAI-ARIA APG Radio Group). Split: Menü-Knopf mit eigenem Namen (aria-label „Weitere Optionen …“), aria-haspopup=menu, aria-expanded, aria-controls; Menü mit Pfeiltasten, Escape gibt den Fokus zurück (APG Menu Button). Zustand nie nur über Farbe (WCAG 1.4.1): Form und Häkchen zeigen die Auswahl. Fokusring sichtbar und vom Auswahlzustand getrennt (2.4.7). Ergebniszahl und Warenkorb per aria-live (4.1.3). Ziele mindestens 44 px (2.5.8 verlangt 24 px). Kontrastmodus: Rahmen an jedem Knopf, Auswahl über Highlight."
 },
 "messwerte": {
  "easing": "cubic-bezier(0.16, 1, 0.3, 1) Öffnen und Form; cubic-bezier(0.7, 0, 0.84, 0) Schließen",
  "dauer_ms": "Druck 150, Form-Morph 220, Menü auf 250 / zu 160, Pfeil 250, Umordnen 250",
  "stagger_ms": "",
  "distanz": "Druck +15 % Breite (flex-grow 1.2 in einer Viererreihe); Menü 6 px von oben, scale .96 → 1",
  "sonstiges": "Abstand verbunden 2 px, innere Ecken 8 px, gedrückt 4 px, gewählt und außen Hälfte der Höhe. Größen 44 / 48 / 56 px. Abstände, Ecken und 15 % aus der MDC-Doku, Dauern und Kurven eigene Festlegung nach Rezept (token-toggle-asymmetrisch).",
  "herkunft": "beobachtet",
  "quelle": "https://gitea.com/784622644/material-components-android/src/branch/master/docs/components/ButtonGroup.md"
 },
 "kurve": {
  "bezier": [
   0.16,
   1.0,
   0.3,
   1.0
  ],
  "css": "cubic-bezier(0.16, 1, 0.3, 1)",
  "name": "expo.out",
  "dauer_ms": 150
 },
 "gesehen_bei": [
  {
   "seite": "Supercharge Design: Material 3 Expressive",
   "url": "https://supercharge.design/blog/material-3-expressive",
   "auszeichnung": "",
   "beobachtung": "Button-Gruppen sind neu in M3 Expressive und ändern Form, Bewegung und Breite der Knöpfe bei Interaktion, von XS bis XL. Der Split-Button hat einen eigenen Menü-Knopf, der sich beim Aktivieren dreht und die Form ändert; fünf Größen wie Label- und Icon-Buttons. Stand der Seite: 02.06.2026.",
   "art": "artikel"
  },
  {
   "seite": "Material Components for Android: ButtonGroup (Doku, Spiegel)",
   "url": "https://gitea.com/784622644/material-components-android/src/branch/master/docs/components/ButtonGroup.md",
   "auszeichnung": "",
   "beobachtung": "Standard-Gruppe mit 12 dp Abstand, jeder Knopf behält seine Form. Verbundene Gruppe: 2 dp Abstand, 8 dp innere Ecken, außen ganz rund. Gedrückter Knopf ändert seine Größe um 15 %. Überlauf-Menü möglich, aber nicht für Auswahl empfohlen.",
   "art": "artikel"
  },
  {
   "seite": "Jetpack Compose: SplitButtonDefaults",
   "url": "https://kotlinlang.org/api/compose-multiplatform/material3/androidx.compose.material3/-split-button-defaults/index.html",
   "auszeichnung": "",
   "beobachtung": "Eigene Werte für innere Ecken in Ruhe und beim Druck je Größe; außen prozentual rund. Der Menü-Knopf (trailing) ist ein Toggle: Wird checked wahr, morphen seine Ecken zu ganz rund.",
   "art": "artikel"
  },
  {
   "seite": "pub.dev: button_group_m3e",
   "url": "https://pub.dev/documentation/button_group_m3e/latest",
   "auszeichnung": "",
   "beobachtung": "Formregel bei Auswahl: gewählter Knopf ganz rund, erster und letzter ungewählt außen rund, mittlere ungewählt eckig. Verbunden heißt Trennfugen statt Abstand. Größen xs bis xl.",
   "art": "demo"
  },
  {
   "seite": "Material Components for Android: IconButton (Doku, Spiegel)",
   "url": "https://gitea.com/784622644/material-components-android/src/branch/master/docs/components/IconButton.md",
   "auszeichnung": "",
   "beobachtung": "Icon-Buttons morphen die Form beim Drücken und beim Auswählen. In Button-Gruppen beeinflussen sie sich gegenseitig beim Drücken. Toggle: ungewählt Kontur-Icon, gewählt gefülltes Icon.",
   "art": "artikel"
  }
 ],
 "tutorials": [
  {
   "titel": "WAI-ARIA APG: Menu Button Pattern",
   "url": "https://w3c.github.io/wai-website/ARIA/apg/patterns/menu-button/"
  },
  {
   "titel": "WAI-ARIA APG: Radio Group Pattern",
   "url": "https://w3c.github.io/wai-website/ARIA/apg/patterns/radio/"
  },
  {
   "titel": "WAI-ARIA APG: Toolbar Example (Toggle-Buttons und Radiogruppe)",
   "url": "https://www.w3.org/WAI/ARIA/apg/example-index/toolbar/toolbar.html"
  }
 ],
 "kombinierbar_mit": [
  "facettenfilter-ergebnisliste",
  "produkt-kaufbox-varianten",
  "tabs-pfeiltasten-focusgroup",
  "gleitender-indikator",
  "button-zustaende",
  "druck-feedback",
  "native-popover-dropdowns",
  "token-toggle-asymmetrisch",
  "flip-zustandswechsel",
  "toast-stapel"
 ],
 "urls": {
  "detail": "https://cecodesign.de/lab/fundus/buttons/button-gruppe-expressiv/",
  "meta": "https://cecodesign.de/lab/fundus/buttons/button-gruppe-expressiv/meta.json",
  "demo": "https://cecodesign.de/lab/fundus/buttons/button-gruppe-expressiv/demo"
 },
 "herkunft": {
  "quelldateien": [
   "Buttons/SR-Recherche 02.11.2026"
  ],
  "pruefnotizen": [
   "Prinzip und Zahlen (2 dp, 8 dp, 15 %) aus Design-System-Dokumentation belegt; eine Produktions-Website im Web mit verbundener Toggle-Gruppe im M3-Expressive-Stil fehlt noch.",
   "Material-Seiten (m3.material.io) waren nicht abrufbar; Werte stammen aus der MDC-Android-Doku (Spiegel auf gitea) und der Compose-API.",
   "Kurven und Dauern sind eigene Festlegung nach Rezept d2c-produkt-zuerst (token-toggle-asymmetrisch), M3 selbst arbeitet mit Federn."
  ]
 },
 "bau": {
  "status": "fertig",
  "kurz": "Verbundene Knopfgruppe nach Material 3 Expressive: Druck macht breiter und eckiger, Auswahl macht rund, der Split-Button öffnet sein Menü mit drehendem Pfeil.",
  "demo": true,
  "abhaengigkeiten": [],
  "werte": {
   "easing": "cubic-bezier(0.16, 1, 0.3, 1) für Druck, Form, Menü auf, FLIP; cubic-bezier(0.7, 0, 0.84, 0) für Menü zu und Ansage aus",
   "dauer_ms": "Druck 150 (mindestens sichtbar 150), Rückweg Breite 250, Form-Morph 220, Farbe 150, Menü auf 250 / zu 160, Pfeil 250, Umordnen FLIP 250, Kaufen laden 700 / Erfolg 1800, Ansage 2800 sichtbar",
   "fuge_px": 2,
   "hoehe_px": "Gruppe 48, Split L 56, Split S 44",
   "ecken_px": "Gruppe innen 8, gedrückt 4, außen und gewählt Hälfte der Höhe (24); Split innen 6 (S 5), gedrückt 14 (S 11), Menü-Knopf offen ganz rund",
   "druck": "flex-grow 1 → 1.2 (in der Viererreihe etwa +15 % Breite), Split-Fläche scale .98 bzw. Menü-Knopf .96",
   "haekchen": "grid-template-columns 0fr → 1fr, 18 px (≤ 480 px: 16 px), Abstand 6 px",
   "menue": "translate 0 -6px → 0, scale .96 → 1, opacity 0 → 1, 8 px unter dem Knopf, rechtsbündig, kippt nach oben, wenn unten kein Platz",
   "farben": "Fläche #E4E0D7, Hover #DAD5CA, gewählt #10714E mit #fff (6:1), Hover gewählt #0D5C40, Hauptaktion #212121 mit #F5F4F1",
   "ziel_min_px": 44
  },
  "ausloeser": "klick",
  "touch": "Kein Hover; Druck über pointerdown sichtbar (mindestens 150 ms). Gruppe nimmt unter 760 px die volle Breite, unter 480 px kürzere Beschriftung (Glashaus) und Auslassung als letzte Rettung. Split-Button volle Breite, Menü bleibt im Viewport.",
  "reduziert": "Alle Übergänge aus: kein Breitenwechsel, kein Skalieren, Ecken und Farbe springen, Menü erscheint ohne Gleiten, Pfeil springt, Umordnen ohne FLIP, Ladekreisel steht.",
  "korrekturen": {
   "umsetzung": "Verbundene Gruppe: display:flex, gap 2px, Knöpfe flex:1 1 0. min-width bleibt auto, damit lange Beschriftungen bei größeren Textabständen nicht abgeschnitten werden; erst unter 480 px min-width:0 mit Auslassung. Ecken über zwei Variablen (links, rechts): innen 8px, außen Hälfte der Höhe in px (nicht 999px, sonst springt die Animation). Druck: Klasse .drueckt bei pointerdown bzw. Leertaste/Enter, mindestens 150 ms, setzt flex-grow 1.2 und innere Ecken 4px. Auswahl: alle Ecken rund, Markengrün, Häkchen fährt über grid-template-columns ein. Toggle: role=toolbar mit Namen, aria-pressed, roving tabindex (Pfeile, Pos1, Ende). Einfachauswahl: role=radiogroup, role=radio, aria-checked, nur der gewählte Knopf hat tabindex=0, Pfeile wählen mit Umlauf. Split: zwei buttons in role=group; Menü-Knopf mit aria-haspopup=menu, aria-expanded, aria-controls, aria-label; Menü als popover mit role=menu, menuitem und menuitemcheckbox, Lage per JS (beforetoggle) unter dem Knopf. Enter, Leertaste und Pfeil runter öffnen und fokussieren den ersten Eintrag, Pfeil hoch den letzten; im Menü Pfeile mit Umlauf, Pos1, Ende, Anfangsbuchstabe, Escape schließt und gibt den Fokus zurück, Tab schließt. Light-Dismiss schließt schon beim pointerdown, deshalb den Offen-Zustand vor dem Klick merken. Ohne Popover-Unterstützung: Attribut entfernen und Klasse .offen. Hauptaktion: Laden (Kreisel, „Wird hinzugefügt …“), Erfolg („Liegt im Korb“, Grün), Ansage per role=status. Nicht lieferbar: aria-disabled mit lesbarem Text und gestrichelter Kante, Menü bleibt bedienbar (Benachrichtigen)."
  },
  "geprueft": "02.11.2026",
  "notiz": "Rezept d2c-produkt-zuerst, Marke Saatkontor Viertor (samenfestes Saatgut) aus Neubrandenburg. Kategorieseite Tomaten mit acht eigenen SVG-Sorten; toggle filtert mit Trefferzahl und Leerzustand, einzeln sortiert per FLIP, Karten öffnen die Produktseite (split) mit Samentüte, Split-Button groß und klein, ausverkaufter Artikel mit bedienbarem Menü. vorfuehren() führt einen gedachten Zeiger durch die aktuelle Variante. Werte für Fuge, Ecken und +15 % aus der MDC-Android-Doku (gitea-Spiegel), Compose SplitButtonDefaults, button_group_m3e; Tastatur nach APG (w3c.github.io, w3.org). Kein Pause-Knopf nötig: ohne Vorführung bewegt sich nichts. Prüfung: Zugang regeln, breite320, textabstand ohne Befund; tastatur meldet die per roving tabindex nicht tabbaren Gruppenknöpfe (gewollt, APG). AD-Review 02.11.2026: Note 4. Saatgut-Shop mit Filter-, Sortier- und Split-Button wirkt wie eine echte Seite; Meldung tastatur:klickbar-nicht-fokussierbar betrifft die per roving tabindex gesteuerten Gruppenknöpfe (gewollt).",
  "varianten": [
   {
    "id": "toggle",
    "name": "Toggle-Gruppe (Mehrfachauswahl)",
    "wann": "Filter mit zwei bis fünf Eigenschaften über einer Ergebnisliste: Shop-Kategorie, Kursplan, Rezepte; mit Trefferzahl und Leerzustand.",
    "werte": {
     "rolle": "role=toolbar, aria-pressed",
     "umordnen": "FLIP 250 ms, nur Position, ausgeblendete Karten ohne Einblendung"
    }
   },
   {
    "id": "einzeln",
    "name": "Einfachauswahl (Radiogruppe)",
    "wann": "Sortierung oder Ansicht mit höchstens fünf Optionen, Antwortwahl im Kurs; nicht für die Größenwahl in der Kaufbox.",
    "werte": {
     "rolle": "role=radiogroup, role=radio, aria-checked",
     "auswahl": "folgt dem Fokus (Pfeiltasten), Druck kurz sichtbar"
    }
   },
   {
    "id": "split",
    "name": "Split-Button mit Menü",
    "wann": "Kaufbox oder Produkt-UI, wenn eine Hauptaktion klare Nebenformen hat (als Geschenk, Paket, merken, erinnern); nicht für gleichwertige oder gefährliche Aktionen.",
    "werte": {
     "hoehe_px": "56 (klein 44)",
     "ecken_px": "innen 6, Druck 14, offen rund",
     "pfeil": "rotate 180deg 250 ms",
     "menue_ms": "auf 250, zu 160",
     "kaufen_ms": "laden 700, Erfolg 1800"
    }
   }
  ]
 }
}
