Interaction — Selection
How users mark/unmark items as selected — single-select, multi-select, range-select, and the visual + accessibility contract for each. Material parity (`/foundations/interaction/selection`). Used by lists, tables, file pickers, chips, and any UI where selection is a primary action.
Spec — Interaction: Selection
Facet *isual*do Koder Design. Material parity: https://m3.material.io/foundations/interaction/selection.
3 selection patterns
| Pattern | Cardinality | Affordance |
|---|---|---|
| *ingle* | 1 of N | Radio button OR row-tap (mutually exclusive) |
| *ultiple* | 0..N | Checkbox OR chip (toggle) OR row-tap+modifier |
| *ange* | contiguous span | Click + Shift+Click; or drag |
R1 — Affordance per cardinality
Single-select
- *adio buttons*when N ≤ 5 and all options must be visible
- *ropdown / select*when N ≥ 6 OR options take vertical room
- *ow-tap*(no visual control) when the selection IS the navigation
(list-detail layout — tapping a row reveals its detail)
Multi-select
- *heckbox*when each item is identified by a row in a list
- *hip*(filter style) when options are short labels, often spatial
(e.g., date ranges, tags)
- *ow
tap with selection mode*— longpress enters selection mode;subsequent taps addremove. Mobile pattern from GmailFiles.
Range-select
- *lick first item, Shift+Click last*— desktop pattern
- *rag*across items — touch and desktop both
- *ate range picker*— specialized component for time
- Always combinable with multi-select (Ctrl+Click toggles individual)
R2 — Visual state per selected item
| State | Marker |
|---|---|
| Unselected | Default surface; no visual marker |
| Selected | Accent-tinted background (low opacity) + checkmark/radio dot + bolder border |
| Hover (selectable, unselected) | Surface-variant background; cursor pointer/finger |
| Hover (selected) | Selected style + slightly elevated tint |
| Focused (keyboard) | 2px focus ring per states.kmd |
| Disabled | Reduced opacity; no hover/focus response |
Selected background opacity recipe: color-mix(in srgb, var(--accent) 12%, transparent) (or theme-equivalent)
R3 — Accessibility
- Selection controls (radio/checkbox) must have:
role="radio"/role="checkbox"if not native<input>(prefer native)aria-checked("true""false""mixed")aria-labelor visible label
- Row-tap selection must announce state change to screen readers via
live region: "Selected. 3 of 12 items."
- Keyboard: Space toggles, arrows navigate (in list/grid), Shift+arrow
extends range, Ctrl+A selects all (if applicable)
R4 — Bulk action affordance
When multi-select is active:
- A *ulk action bar*appears (top of list or floating) with:
- Count: "3 selected"
- Primary actions: Delete, Archive, Tag (per surface)
- Cancel / Deselect all
- Bar uses *elected color scheme*— accent
tinted, not errortinted,even for destructive actions (preserve destructive semantics inside per-button styling)
- Bar is reachable by keyboard (Tab from any selected row)
R5 — Persistence
Selection state is *phemeral*by default — refreshing the page clears.
Exception: when the user navigates within a single workflow (e.g., list → detail → back), restore the previously selected item. Use URL fragment or session storage; clear on workflow exit.
R6 — Edge cases
- *mpty list with selection mode*— exit selection mode automatically
- *ll items selected*— show "Deselect all" instead of "Select all"
- *ixed state*(some descendants selected in a tree) — checkbox shows
aria-checked="mixed"and indeterminate visual - *election during async load*— preserve user intent; if items
rearrange, keep selection by ID not by index
Cross-link
interaction/states.kmd— focushoverpressed/disabled detailsfoundations/elements.kmd— selection is a control affordancethemes/color-schemes.kmd— accent-tinted background token