Button groups — Expressive extension

mandatory

Material 3 Expressive extension to base button groups (specs/components/buttons.kmd §Button groups). Adds 5 sizes (XS-XL), connected appearance (no gap + shared corners), shape/motion transformations on hover/press via spring. Strictly extends; baseline buttons.kmd remains valid.

Spec — Button groups Expressive

Strict extension to buttons.kmd §Button groups. Compatible: code using base button groups remains valid; Expressive opt-in per surface OR per preset.

Princípios

  1. *onnected by default*— sem gap entre items; visual unified group.
  2. * sizes XS-XL*— granular sizing extending baseline 3 sizes.
  3. *hape morph on press*— corner radius pulls toward pressed item.
  4. *cale on hover*— 1.0 → 1.05 via spring (desktop + tablet hover).
  5. *educedmotion safe*— animations skipped under `prefersreduced-motion`.

R1 — Anatomy (extension)

Base anatomy per buttons.kmd §Button groups. Expressive adds:

   normal:    ┌──┬──┬──┬──┐
              │ A│ B│ C│ D│
              └──┴──┴──┴──┘
   hover B:   ┌──┬────┬──┬──┐   ← B scales 1.05 + neighbors compress
              │ A│  B │ C│ D│
              └──┴────┴──┴──┘
   press C:   ┌──┬──┬──┬──┐
              │ A│ B│CCC│ D│   ← C grabs visual focus
              └──┴──┴──┴──┘

R2 — 5 sizes

Size Item height (dp) Padding L+R Min item width
XS 28 8 48
S 32 10 56
M 40 16 64
L 48 20 72
XL 56 24 80

R3 — Connected appearance

  • No gap entre items (0dp).
  • Shared inner border (1dp; color outline-variant).
  • Group radius: shape-corner-small or shape-corner-medium (per preset; xs/sm in expressive default).
  • Items at edges share group radius; inner items square.

R4 — Hover state

Hover an item (desktop/mouse OR tablet stylus-hover):

  • Scale: 1.0 → 1.05 over 200ms spring motion-spatial-fast (per motion.kmd R9.1).
  • Neighbors compress slightly (max 5% width reduction) to make room.
  • Group radius shifts toward hovered item.
  • Color shift: hovered item background surface-container-highest.

R5 — Press state

Press item:

  • Scale: 1.0 → 0.97 (subtle "click" feel) via spring.
  • Group radius "pulls toward" pressed item (radius asymmetric briefly).
  • Color: primary-container (filled style) OR primary text (outlined).
  • Release: spring back to default state.

R6 — Selected state (for toggle groups)

Selected item in toggle group:

  • Background: secondary-container (tonal).
  • Persistent (not press-flash).
  • Shape: filled in corner radius of group.

Multiselect OR singleselect per host config.

R7 — Surface bindings

Surface API
Flutter Extension of KoderButtonGroup (per buttons.kmd); pass expressive: true flag
Web <koder-button-group expressive>
Compose KoderButtonGroup(expressive = true)
SwiftUI idem
CLI / TUI Flat text; expressive ignored

R8 — Acessibilidade

  • Buttons individually focusable per buttons.kmd.
  • Hover scale: visual only — does NOT affect tab order.
  • Reduced-motion: hover scale + radius shift disabled; color shift remains.
  • Touch target ≥ 28dp per size XS (sizes S+ already meet 32+).

R9 — i18n

Inherits from buttons.kmd. No new keys.

R10 — Per-preset variation

Preset Expressive button group
material3 Subtle expressive (smaller scale 1.02; weaker shape morph)
material_expressive Full expressive (defaults from this spec)
material2 Disabled — falls back to baseline buttons.kmd
terminal_classic Plain [A][B][C] text — no expressive
brutalist No hover scale; no shape morph; sharp corners only
cyberpunk_neon Default + glow on hovered/pressed
minimalist_mono Hover changes underline only; no scale/morph

T-suite

  • *1*Render 3-item group XS → height 28dp; min width 48dp each.
  • *2*Hover item: scale 1.0 → 1.05 via spring; neighbors compress.
  • *3*Press item: scale → 0.97; release → springs back.
  • *4*Group radius asymmetric during press; reverts on release.
  • *5*Selected state: persistent secondary-container fill.
  • *6*Reduced-motion: no scale + no shape morph; color shift kept.
  • *7*Touch target ≥ 28dp for XS; S+ ≥ 32dp.
  • *8*Disable expressive (flag false): falls back to base buttons.kmd behavior.
  • *9*A11y: tab order unchanged by scale.
  • *1*Material2 preset: expressive ignored (graceful).

Source: ../home/koder/dev/koder/meta/docs/stack/specs/components/button-groups-expressive.kmd