Buttons
Button system — 7 variants (filled, tonal, outlined, text, elevated, icon, FAB), button groups, segmented buttons. Material parity (`/components/all-buttons`, `/components/buttons`, `/components/button-groups`). Covers anatomy, hierarchy, states, accessibility, and per-preset shape variation.
Spec — Buttons
Facet *isual*do Koder Design. Material parity: https://m3.material.io/components/all-buttons.
Covers
#049.21(button groups),#049.22(segmented),#049.23(icon button),#049.24(FAB / extended FAB).
7 button variants
| Variant | Visual | Use |
|---|---|---|
| *illed* | Solid accent bg + accent-on text | Primary action (1 per surface) |
| *onal* | Surface-variant bg + text | Secondary action, less emphasis than filled |
| *utlined* | Transparent bg + accent border + accent text | Secondary, with stronger structure than text |
| *ext* | No bg, no border, accent text | Tertiary action, footer links, dismissive |
| *levated* | Surface bg + shadow level 1 + accent text | "Picked up" button when surrounding flat |
| *con* | 24px icon, no label, surface or transparent bg | Action without a label (toolbar) |
| *AB* | Round (radius-full or xl) + accent fill + icon | Primary action shortcut, floats above |
Plus 1 derivative: *xtended FAB*= FAB with text label beside the icon. Same visual treatment, broader.
Anatomy
┌──────────────────────────┐
│ [icon?] Label [icon?] │ ← container (radius-sm default)
└──────────────────────────┘
pad-x pad-x- *ontainer* 40 px height default (32 px small, 56 px large)
- *abel*
label-largetype role (14/20, weight 500) - *ptional leading icon* 18 px, 8 px gap to label
- *ptional trailing icon* 18 px, 8 px gap from label
- *adding* 24 px horizontal (16 px if icon-only or compact)
FAB anatomy:
- 56×56 px (default) or 96×96 (large) or 40×40 (small)
- Single icon, no label (extended FAB adds label)
- Radius:
radius-xl(default) orradius-full(per preset) - Elevation: level 3 default, level 4 on hover
R1 — Hierarchy per surface
| Allowed count | Variant | Role |
|---|---|---|
| At most 1 | Filled OR Elevated | Primary action |
| 0..N | Tonal OR Outlined | Secondary actions |
| 0..N | Text | Tertiary, dismissive |
| At most 1 | FAB | Surface-wide primary action (overrides Filled hierarchy on mobile) |
Destructive actions: use Outlined OR Text style with error color token, never Filled red (Filledred overemphasizes; the action itself is enough warning).
R2 — Sizes
| Size | Height | Pad-x | Label role |
|---|---|---|---|
| Small | 32 | 16 | label-medium |
| Default | 40 | 24 | label-large |
| Large | 56 | 32 | title-medium |
Tap target: minimum 48 px touch area enforced via outer hit-zone expansion even on Small (visible 32 px, hit zone 48 px).
R3 — States
Per interaction/states.kmd:
| State | Filled | Tonal | Outlined | Text | Elevated | Icon | FAB |
|---|---|---|---|---|---|---|---|
| Hover | +8% overlay | +8% overlay | accent 8% bg | 8% bg | elevation +1 | 8% bg | elevation +1 |
| Focus | + focus ring | + focus ring | thicker border + ring | accent bg | + focus ring | + focus ring | + focus ring |
| Press | +12% overlay + ripple | +12% + ripple | +12% bg + ripple | 12% bg + ripple | elevation 0 + ripple | 12% bg + ripple | elevation 2 + ripple |
| Disabled | 38% opacity | 38% opacity | 38% opacity | 38% opacity | 38% opacity | 38% opacity | 38% opacity |
R4 — Button groups
Multiple related buttons rendered together as a unit.
┌──────┬──────┬──────┐
│ Day │ Week │ Month│ ← single rounded container, dividers between
└──────┴──────┴──────┘*ules*
- Buttons share visual container (corner radius applies to OUTER container, not each button)
- Inner dividers
1px solid border - All buttons same variant (don't mix filled + outlined in one group)
- Same height across all buttons in group
- Equal width (stretch to fill) OR content-sized (per design)
R5 — Segmented button
A button group used for single-select (exclusive choice).
- Visual: same as button group
- Selected state: accent
tinted background (`accenttint` 12%) + accent text + checkmark icon (Material adds checkmark) - One must always be selected; can't all be off
role="radiogroup"+role="radio"on each segment (or native radio + label styling)
R6 — Icon-only buttons
- 40×40 px square (default size), 32×32 small, 56×56 large
- Single icon centered, 24 px (default)
aria-labelREQUIRED (no visible label means accessible name must come fromaria-label)- Tooltip on hover/focus showing the action name (per future tooltips.kmd)
R7 — FAB placement
| Position | Convention |
|---|---|
| Bottom-right | Default mobile (avoids overlapping bottom |
| Bottom-center | Within a bottom app bar (centered FAB pattern) |
| Top-right (desktop) | Optional on Expanded/Large class |
Margin from screen edge: 16 dp (Compact), 24 dp (Medium+). Avoid overlapping content; reserve safearea space per `safearea.kmd`.
R8 — Accessibility
- Minimum touch target 48×48 px (R2)
<button>element (native; not<div onclick>)- Visible focus ring (
focus-visible, 2 px solidfocuscolor, 2 px offset) aria-labelfor icon-onlyaria-pressedfor toggle buttonsaria-disabledfor disabled (still focusable for keyboard announcement)- Loading state:
aria-busy="true"+ visible spinner
R9 — Per-preset variation
Each preset (per themes/ui-style.kmd) varies button shape:
material3: radius-sm (8 px)material2: radius-sm (4 px — sharper)windows_95: radius-none (0 px) + 3D bevel bordersios_cupertino: radius-md (14 px — softer)brutalist: radius-none + thick border (3 px)glassmorphism: radius-md + backdrop blur background
Full table: themes/shape.kmd R3.
R10 — Forbidden patterns
- ❌ More than 1 Filled button per surface
- ❌ Filled red for destructive (use Outlined+error)
- ❌ Buttons inside buttons
- ❌ Variable button heights within a button group
- ❌ Custom hex colors (must come from
accenterrorsuccesstokens) - ❌ Tap targets smaller than 48 px effective hit area
Cross-link
interaction/states.kmd— state overlay opacitiesthemes/color-roles.kmd— accent + accent-on bindingsthemes/shape.kmd— radius per presetthemes/elevation.kmd— elevated variant + FAB elevationthemes/typography.kmd— label-large default rolefoundations/elements.kmd— Control family