Interaction — Selection

mandatory

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)

  • *owtap 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-label or 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*— accenttinted, 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

  • interaction/states.kmd — focushoverpressed/disabled details
  • foundations/elements.kmd — selection is a control affordance
  • themes/color-schemes.kmd — accent-tinted background token

Source: ../home/koder/dev/koder/meta/docs/stack/specs/interaction/selection.kmd