UX Decision Rubrics
Overview
Two rubrics that turn "make it better" into measurable, defensible calls — so a UI decision is backed by a rule you can defend to a stakeholder (NN/g, Baymard, WCAG), not personal taste.
- Rubric A — Component Choice: which control belongs on which job. A default rule plus one decisive test settle most arguments in a single line.
- Rubric B — User-Story Clarity Scoring: which flows to redesign, scored 1–5 on 7 dimensions so "this feels clunky" becomes a number with a threshold and a ranking.
The whole value is the same discipline that makes an audit trustworthy: decide by the rubric first, then implement — never pick by feel and back-fill a reason. Cite the rule inline so the decision survives review.
When to use
- "Which control should this be — a select or a combobox? a toggle or a checkbox?"
- "Is this flow clear enough to ship, or does it need a redesign?"
- "Prove this redesign is objectively better." / "Why is this the right control?"
- Setting acceptance criteria for a UI change (definition of done a reviewer can check).
- Ranking a backlog of screens/flows by where redesign effort actually pays off.
When NOT to use this skill
- Pure brand / visual-identity work (typography personality, color story, art direction) → use
frontend-design. These rubrics judge fit-to-job and clarity, not aesthetic taste.
- Implementing the chosen control (accessible primitive, tokens, focus ring) → use
shadcn-tailwind-v4-primitives.
- Mechanically verifying the Mobile-parity row (overflow, tap-target, input-zoom) → use
empirical-responsive-audit — render it, don't eyeball it.
Rubric A — Component Choice
The default rule
Fewer options → more-visible control. As the option count and dynamism drop, move up this ladder:
segmented / buttons > radio group > select > combobox
- A binary that applies instantly (no Save) → toggle.
- A binary submitted with a form → checkbox.
The decisive toggle-vs-checkbox test (NN/g)
Is there an instant cause-and-effect with NO Save button? → toggle.
Is the value collected and applied on Submit? → checkbox.
Never mix instant toggles inside a Submit-button form. A switch tells the user "this already took effect"; if it actually waits for Save, you have broken the control's core contract. When in doubt, ask "does flipping it change the world right now?" — yes ⇒ toggle, no ⇒ checkbox.
Fast path — pick a control in 3 questions
- Is it a binary (on/off)? Instant, no Save → toggle. Submitted with a form → checkbox.
- Is it 1-of-N? N≤5 all worth showing → segmented (parallel views) or radio (options, on submit); up to ~7–10, no search → select; long / dynamic / searchable → combobox.
- Is it an action, not a value? Now → button (one primary per view) or menu (overflow/row actions). App-wide nav + actions → command palette.
The full table
| Control |
Use it when |
Don't — use instead |
| Text input |
short free-form single value (name, subdomain, note) |
value has a known finite set → select / radio / combobox |
| Textarea |
multi-line / long free-form value (description, DNS TXT body) |
a single logical short value → text input |
| Select (Radix) |
pick 1 of a small known list (≤~7–10), no search needed |
list is long/searchable → combobox; or ≤5 options worth showing at once → segmented / radio |
| Combobox (input + listbox) |
pick 1 of a long / dynamic / searchable list, or free-entry-with-suggestions. Workhorse for country / timezone / domain pickers |
static short list → select |
Command palette (⌘/Ctrl-K, cmdk) |
global nav + actions app-wide for power users |
selecting one field value inside a form → combobox. It is a different job than a field combobox |
| Radio group |
pick 1 of 2–5 mutually-exclusive options, all worth showing, effect on submit. Always give a default |
on/off → toggle; many options → select |
| Checkbox group (multi) |
choose 0-to-many independent options |
options are mutually exclusive → radio |
| Single checkbox |
one binary submitted with a form ("I agree", "also add www") |
takes effect instantly → toggle |
| Toggle / Switch |
a binary that takes effect immediately, no Save |
needs Submit/confirm, or is destructive → checkbox / confirm dialog |
| Segmented / toggle-group |
switch between 2–5 parallel views or modes (All / Active / Errored; JSON / Table) |
yes/no → toggle |
| Button |
trigger an action or navigation now. One primary per view |
it represents state → toggle / checkbox |
| Menu (dropdown) |
secondary / overflow actions on a row or object (rename / delete / re-verify) |
choosing a form value → select |
| Number input (+ presets) |
an exact numeric value (TTL, port, priority) |
an imprecise range → slider (rare) |
| Date picker |
a specific date/time |
experts type a range faster — also allow text entry |
| Slider |
an imprecise value in a continuous range |
exact value matters → number input |
Common mistakes (all objectively wrong per the table)
- Segmented control used for yes/no — it's for parallel views, not a binary state. Use a toggle.
- A native
<select> where a searchable combobox is needed — e.g. the full ~195-item country list. No type-ahead = a findability failure. Use a combobox.
- A toggle used for a value that only applies on Save — breaks the instant cause-and-effect contract. Use a checkbox.
Rubric B — User-Story Clarity Scoring
For each key job-to-be-done (not each page — the whole task, e.g. "connect a custom domain"), score all 7 dimensions 1–5. Anchor the scale: 1 = broken/absent, 3 = works but with friction, 5 = exemplary.
| # |
Dimension |
Score 1–5 on whether the flow… |
| 1 |
Findability |
lets the user locate where to start in ≤2 clicks or one ⌘-K query |
| 2 |
Clarity of next step |
makes the single primary action obvious on every screen |
| 3 |
Input forgiveness |
accepts messy input, normalizes it, and prevents errors |
| 4 |
Feedback / status |
keeps system status visible at every async step (nothing silent) |
| 5 |
Recoverability |
lets the user undo / cancel and recover from any error — no dead-ends |
| 6 |
Mobile parity |
is fully completable on mobile (no h-scroll, 44px targets, 16px inputs, thumb-reachable primary) |
| 7 |
Expert efficiency |
offers a keyboard / ⌘-K / API path for repeat use |
The scoring rules (non-negotiable)
- Any dimension ≤2 = a defect to fix before ship — a ship-blocker on its own, regardless of the total. Never average a 2 away.
- Task total < 28/35 → redesign that flow. (28 = a mean of 4 across the seven.)
- Track the scores per release to catch regressions — a flow that was 31 dropping to 26 is a signal.
- Rank flows by (low score × high value) so the redesign starts where it matters, not where it's easiest.
Copy-paste scorecard (fill one per flow)
Flow: <job-to-be-done> Value: <High | Med | Low>
1 Findability [ ]/5
2 Clarity of next step [ ]/5
3 Input forgiveness [ ]/5
4 Feedback / status [ ]/5
5 Recoverability [ ]/5
6 Mobile parity [ ]/5
7 Expert efficiency [ ]/5
─────────────────────────────────
TOTAL [ ]/35
Verdict: total <28 → REDESIGN. Any dimension ≤2 → DEFECT (blocks ship) even if total ≥28.
Priority = (35 − total) × value. # rank the backlog by this
Supporting principles — smart inputs
These are how you earn points 3–4 on Rubric B, and the acceptance criteria for any input you build.
- Schema-first validation, shared client + server via
zod. One schema, both sides — the client and server can never drift.
- Inline, reward-early / punish-late. Validate a field the moment it becomes valid; surface its error only after the user leaves it invalid. Put the error below the field, with an icon + text (never a placeholder, never color-only).
- Prevent errors over messaging them. Constrain the input (masks, steppers, pickers,
<select>) so the invalid state is unreachable in the first place.
- Normalize, don't reject. Trim, lowercase, strip protocol, coerce — accept
"Https://Foo.COM/ " and store foo.com. Rejecting what you could have fixed is a self-inflicted error.
- Color is never the only signal. If the palette is monochrome, carry status by icon + text + weight, NOT color alone (WCAG 1.4.1). A red-only "invalid" is invisible to many users and in grayscale.
Mobile-correctness acceptance criteria
Paste these into the ticket as the definition of done for the Mobile-parity dimension; verify with empirical-responsive-audit:
Output
A decision, not an essay. Two deliverable shapes:
Component choice — a one-line decision record that cites the rule:
Country picker → combobox (searchable), not a native <select>. Rubric A: 1-of-a-long-list with search needed; a ~195-item native select fails Findability. Cite: NN/g complex-application design.
"Also add www" → single checkbox, not a toggle. Rubric A / toggle-test: the value is applied on Submit with the form, so it is a checkbox — a toggle would falsely promise an instant effect.
Flow review — the filled scorecard(s) plus a rollup:
- One scorecard per key job (template above), each with its total, any ≤2 defects flagged, and Value.
- A redesign list ranked by
(35 − total) × value — the flow at the top is where redesign pays off first.
- The mobile acceptance-criteria checklist attached to any flow whose Mobile-parity scored ≤3.
Pitfalls
- Deciding by taste, then back-filling a rule. Run the rubric first; the rule is the decision, not the rationalization. If you can't cite one, you haven't decided objectively yet.
- A toggle inside a Submit-button form. The instant cause-and-effect contract is broken — users think it already applied. It's a checkbox.
- A segmented control for yes/no. It reads as two parallel views, not a binary state. It's a toggle.
- A native
<select> for a long/searchable list. No type-ahead filtering; scrolling 195 items is a Findability failure. It's a combobox.
- Averaging a defect away. A dimension at 2 blocks ship even if the total clears 28. Report the low dimension explicitly; don't hide it in the mean.
- Scoring a flow you never ran. Feedback/status, Recoverability, and Mobile-parity can only be scored by driving the flow — reading the code under-detects them. Pair with
empirical-responsive-audit for the mobile row.
- Color-only status. Fails WCAG 1.4.1 and vanishes in a monochrome palette. Add icon + text + weight.
Sources
The rubrics are defensible because each rule traces to published guidance:
- NN/g — Toggle-Switch Guidelines (the toggle-vs-checkbox test), Complex-Application Design (control density / visibility ladder), 10 Usability Heuristics (visibility of system status → Feedback; user control & error recovery → Recoverability), Bottom Sheets.
- Baymard — Form Design (inline validation, error prevention; never use inline/placeholder labels).
- Refactoring UI — hierarchy and spacing carried by weight/size/space, not color alone.
- WCAG 2.2 — 2.5.5 Target Size (Enhanced, AAA) is the 44px figure we adopt (2.5.8 Target Size (Minimum), AA, requires only ≥24px); 1.4.4/1.4.10 resize & reflow (keep pinch-zoom); 1.4.1 use of color (status ≠ color alone). The ≥16px input rule is iOS auto-zoom prevention — WCAG-adjacent, not a criterion.
- shadcn/ui + Radix — the accessible primitive layer these controls should be built on.
Combining with other skills
shadcn-tailwind-v4-primitives — once Rubric A picks the control, scaffold it correctly (accessible Radix primitive, semantic tokens, focus ring, 44px targets). Rubric decides which; that skill builds it.
empirical-responsive-audit — verify the Mobile-parity dimension and the mobile acceptance criteria mechanically by rendering, instead of scoring by eye.
ui-ux-audit — the companion hand-checklist; run it alongside Rubric B for the qualitative pass on a specific dashboard.
dark-mode-token-migration — when a flow scores low on Feedback/status because it leans on color, the semantic token layer is where you fix status semantics (icon + text + token, not raw color).
parallel-agent-refactor — when Rubric B flags many flows for redesign, fan the per-flow fixes out across parallel write-agents (one disjoint slice each).
production-agent-audit — the same "objective, evidence-bound, defensible-to-a-stakeholder" philosophy applied to a live agent platform instead of a UI; reach for it when the thing under review is agent behavior, not screens.
1---2name: ux-decision-rubrics3description: Make UI/UX calls objectively with two rubrics instead of by taste. Rubric A picks the right form control via decisive rules like NN/g's toggle-vs-checkbox test; Rubric B scores each key user flow 1–5 across 7 clarity dimensions to flag which to redesign. Use when choosing a form control, judging whether a flow needs redesign, justifying "objectively better" to a stakeholder, or writing UI acceptance criteria. Not for pure brand/visual work — use `frontend-design`.4---56# UX Decision Rubrics78## Overview9Two rubrics that turn "make it better" into **measurable, defensible calls** — so a UI decision is backed by a rule you can defend to a stakeholder (NN/g, Baymard, WCAG), not personal taste.1011- **Rubric A — Component Choice:** which control belongs on which job. A default rule plus one decisive test settle most arguments in a single line.12- **Rubric B — User-Story Clarity Scoring:** which flows to redesign, scored 1–5 on 7 dimensions so "this feels clunky" becomes a number with a threshold and a ranking.1314The whole value is the same discipline that makes an audit trustworthy: **decide by the rubric first, then implement — never pick by feel and back-fill a reason.** Cite the rule inline so the decision survives review.1516## When to use17- "Which control should this be — a select or a combobox? a toggle or a checkbox?"18- "Is this flow clear enough to ship, or does it need a redesign?"19- "Prove this redesign is *objectively* better." / "Why is this the right control?"20- Setting **acceptance criteria** for a UI change (definition of done a reviewer can check).21- Ranking a backlog of screens/flows by where redesign effort actually pays off.2223## When NOT to use this skill24- **Pure brand / visual-identity work** (typography personality, color story, art direction) → use `frontend-design`. These rubrics judge *fit-to-job and clarity*, not aesthetic taste.25- **Implementing** the chosen control (accessible primitive, tokens, focus ring) → use `shadcn-tailwind-v4-primitives`.26- **Mechanically verifying** the Mobile-parity row (overflow, tap-target, input-zoom) → use `empirical-responsive-audit` — render it, don't eyeball it.2728---2930## Rubric A — Component Choice3132### The default rule33**Fewer options → more-visible control.** As the option count and dynamism drop, move up this ladder:3435`segmented / buttons > radio group > select > combobox`3637- A **binary that applies instantly** (no Save) → **toggle**.38- A **binary submitted with a form** → **checkbox**.3940### The decisive toggle-vs-checkbox test (NN/g)41> **Is there an instant cause-and-effect with NO Save button?** → **toggle**.42> **Is the value collected and applied on Submit?** → **checkbox**.4344**Never mix instant toggles inside a Submit-button form.** A switch tells the user "this already took effect"; if it actually waits for Save, you have broken the control's core contract. When in doubt, ask "does flipping it change the world *right now*?" — yes ⇒ toggle, no ⇒ checkbox.4546### Fast path — pick a control in 3 questions471. **Is it a binary (on/off)?** Instant, no Save → **toggle**. Submitted with a form → **checkbox**.482. **Is it 1-of-N?** N≤5 all worth showing → **segmented** (parallel views) or **radio** (options, on submit); up to ~7–10, no search → **select**; long / dynamic / searchable → **combobox**.493. **Is it an action, not a value?** Now → **button** (one primary per view) or **menu** (overflow/row actions). App-wide nav + actions → **command palette**.5051### The full table52| Control | Use it when | Don't — use instead |53|---|---|---|54| **Text input** | short free-form single value (name, subdomain, note) | value has a known finite set → `select` / `radio` / `combobox` |55| **Textarea** | multi-line / long free-form value (description, DNS TXT body) | a single logical short value → `text input` |56| **Select (Radix)** | pick 1 of a small known list (≤~7–10), no search needed | list is long/searchable → `combobox`; or ≤5 options worth showing at once → `segmented` / `radio` |57| **Combobox (input + listbox)** | pick 1 of a long / dynamic / searchable list, or free-entry-with-suggestions. **Workhorse for country / timezone / domain pickers** | static short list → `select` |58| **Command palette (⌘/Ctrl-K, `cmdk`)** | **global** nav + actions app-wide for power users | selecting one field value inside a form → `combobox`. It is a different job than a field combobox |59| **Radio group** | pick 1 of 2–5 mutually-exclusive options, all worth showing, effect on submit. **Always give a default** | on/off → `toggle`; many options → `select` |60| **Checkbox group (multi)** | choose 0-to-many **independent** options | options are mutually exclusive → `radio` |61| **Single checkbox** | one binary **submitted with a form** ("I agree", "also add `www`") | takes effect instantly → `toggle` |62| **Toggle / Switch** | a binary that takes effect **immediately, no Save** | needs Submit/confirm, or is destructive → `checkbox` / confirm dialog |63| **Segmented / toggle-group** | switch between 2–5 **parallel views or modes** (All / Active / Errored; JSON / Table) | yes/no → `toggle` |64| **Button** | trigger an action or navigation **now**. One **primary** per view | it represents *state* → `toggle` / `checkbox` |65| **Menu (dropdown)** | secondary / overflow actions on a row or object (rename / delete / re-verify) | choosing a form value → `select` |66| **Number input (+ presets)** | an **exact** numeric value (TTL, port, priority) | an imprecise range → `slider` (rare) |67| **Date picker** | a specific date/time | experts type a range faster — also allow text entry |68| **Slider** | an imprecise value in a continuous range | exact value matters → `number input` |6970### Common mistakes (all objectively wrong per the table)71- **Segmented control used for yes/no** — it's for *parallel views*, not a binary state. Use a toggle.72- **A native `<select>` where a searchable combobox is needed** — e.g. the full ~195-item country list. No type-ahead = a findability failure. Use a combobox.73- **A toggle used for a value that only applies on Save** — breaks the instant cause-and-effect contract. Use a checkbox.7475---7677## Rubric B — User-Story Clarity Scoring7879For **each key job-to-be-done** (not each page — the whole task, e.g. "connect a custom domain"), score all 7 dimensions **1–5**. Anchor the scale: **1 = broken/absent, 3 = works but with friction, 5 = exemplary.**8081| # | Dimension | Score 1–5 on whether the flow… |82|---|---|---|83| 1 | **Findability** | lets the user locate where to start in **≤2 clicks or one ⌘-K query** |84| 2 | **Clarity of next step** | makes the **single primary action obvious on every screen** |85| 3 | **Input forgiveness** | accepts messy input, **normalizes** it, and **prevents** errors |86| 4 | **Feedback / status** | keeps **system status visible at every async step** (nothing silent) |87| 5 | **Recoverability** | lets the user **undo / cancel and recover from any error — no dead-ends** |88| 6 | **Mobile parity** | is **fully completable on mobile** (no h-scroll, 44px targets, 16px inputs, thumb-reachable primary) |89| 7 | **Expert efficiency** | offers a **keyboard / ⌘-K / API path** for repeat use |9091### The scoring rules (non-negotiable)92- **Any dimension ≤2 = a defect to fix before ship** — a ship-blocker on its own, *regardless of the total*. Never average a 2 away.93- **Task total < 28/35 → redesign that flow.** (28 = a mean of 4 across the seven.)94- **Track the scores per release** to catch regressions — a flow that was 31 dropping to 26 is a signal.95- **Rank flows by (low score × high value)** so the redesign starts where it matters, not where it's easiest.9697### Copy-paste scorecard (fill one per flow)98```99Flow: <job-to-be-done> Value: <High | Med | Low>100 1 Findability [ ]/5101 2 Clarity of next step [ ]/5102 3 Input forgiveness [ ]/5103 4 Feedback / status [ ]/5104 5 Recoverability [ ]/5105 6 Mobile parity [ ]/5106 7 Expert efficiency [ ]/5107 ─────────────────────────────────108 TOTAL [ ]/35109 Verdict: total <28 → REDESIGN. Any dimension ≤2 → DEFECT (blocks ship) even if total ≥28.110 Priority = (35 − total) × value. # rank the backlog by this111```112113---114115## Supporting principles — smart inputs116These are how you *earn* points 3–4 on Rubric B, and the acceptance criteria for any input you build.117118- **Schema-first validation, shared client + server via `zod`.** One schema, both sides — the client and server can never drift.119- **Inline, reward-early / punish-late.** Validate a field the moment it becomes valid; surface its error only **after** the user leaves it invalid. Put the error **below the field, with an icon + text** (never a placeholder, never color-only).120- **Prevent errors over messaging them.** Constrain the input (masks, steppers, pickers, `<select>`) so the invalid state is unreachable in the first place.121- **Normalize, don't reject.** Trim, lowercase, strip protocol, coerce — accept `"Https://Foo.COM/ "` and store `foo.com`. Rejecting what you could have fixed is a self-inflicted error.122- **Color is never the only signal.** If the palette is monochrome, carry status by **icon + text + weight, NOT color alone** (WCAG 1.4.1). A red-only "invalid" is invisible to many users and in grayscale.123124## Mobile-correctness acceptance criteria125Paste these into the ticket as the definition of done for the Mobile-parity dimension; verify with `empirical-responsive-audit`:126- [ ] Inputs use **≥16px** font (prevents iOS auto-zoom-on-focus).127- [ ] Interactive targets are **≥44px** (WCAG **2.5.5** Target Size (Enhanced, AAA) / Apple HIG; SC **2.5.8** Target Size (Minimum), AA, requires only ≥24px — we adopt the stronger 44px).128- [ ] Layout respects **safe-area insets** (`env(safe-area-inset-*)`).129- [ ] **Vertical-only scroll** — zero horizontal overflow at every breakpoint.130- [ ] **Pinch-zoom is KEPT** — never `maximum-scale=1` / `user-scalable=no` (WCAG 1.4.4).131132---133134## Output135A decision, not an essay. Two deliverable shapes:136137**Component choice — a one-line decision record that cites the rule:**138> **Country picker → `combobox`** (searchable), not a native `<select>`. Rubric A: 1-of-a-long-list **with search needed**; a ~195-item native select fails Findability. *Cite: NN/g complex-application design.*139140> **"Also add `www`" → single `checkbox`**, not a toggle. Rubric A / toggle-test: the value is **applied on Submit with the form**, so it is a checkbox — a toggle would falsely promise an instant effect.141142**Flow review — the filled scorecard(s) plus a rollup:**143- One scorecard per key job (template above), each with its total, any ≤2 defects flagged, and Value.144- A **redesign list ranked by `(35 − total) × value`** — the flow at the top is where redesign pays off first.145- The **mobile acceptance-criteria checklist** attached to any flow whose Mobile-parity scored ≤3.146147## Pitfalls148- **Deciding by taste, then back-filling a rule.** Run the rubric *first*; the rule is the decision, not the rationalization. If you can't cite one, you haven't decided objectively yet.149- **A toggle inside a Submit-button form.** The instant cause-and-effect contract is broken — users think it already applied. It's a checkbox.150- **A segmented control for yes/no.** It reads as two parallel views, not a binary state. It's a toggle.151- **A native `<select>` for a long/searchable list.** No type-ahead filtering; scrolling 195 items is a Findability failure. It's a combobox.152- **Averaging a defect away.** A dimension at 2 blocks ship even if the total clears 28. Report the low dimension explicitly; don't hide it in the mean.153- **Scoring a flow you never ran.** Feedback/status, Recoverability, and Mobile-parity can only be scored by **driving the flow** — reading the code under-detects them. Pair with `empirical-responsive-audit` for the mobile row.154- **Color-only status.** Fails WCAG 1.4.1 and vanishes in a monochrome palette. Add icon + text + weight.155156## Sources157The rubrics are defensible because each rule traces to published guidance:158- **NN/g** — *Toggle-Switch Guidelines* (the toggle-vs-checkbox test), *Complex-Application Design* (control density / visibility ladder), *10 Usability Heuristics* (visibility of system status → Feedback; user control & error recovery → Recoverability), *Bottom Sheets*.159- **Baymard** — *Form Design* (inline validation, error prevention; **never use inline/placeholder labels**).160- **Refactoring UI** — hierarchy and spacing carried by weight/size/space, **not color alone**.161- **WCAG 2.2** — **2.5.5** Target Size (Enhanced, AAA) is the 44px figure we adopt (**2.5.8** Target Size (Minimum), AA, requires only ≥24px); **1.4.4**/**1.4.10** resize & reflow (keep pinch-zoom); **1.4.1** use of color (status ≠ color alone). The **≥16px input** rule is **iOS auto-zoom prevention** — WCAG-adjacent, not a criterion.162- **shadcn/ui + Radix** — the accessible primitive layer these controls should be built on.163164## Combining with other skills165- `shadcn-tailwind-v4-primitives` — once Rubric A picks the control, scaffold it correctly (accessible Radix primitive, semantic tokens, focus ring, 44px targets). Rubric decides *which*; that skill builds *it*.166- `empirical-responsive-audit` — verify the **Mobile-parity** dimension and the mobile acceptance criteria **mechanically by rendering**, instead of scoring by eye.167- `ui-ux-audit` — the companion hand-checklist; run it alongside Rubric B for the qualitative pass on a specific dashboard.168- `dark-mode-token-migration` — when a flow scores low on Feedback/status because it leans on color, the semantic token layer is where you fix status semantics (icon + text + token, not raw color).169- `parallel-agent-refactor` — when Rubric B flags many flows for redesign, fan the per-flow fixes out across parallel write-agents (one disjoint slice each).170- `production-agent-audit` — the same "objective, evidence-bound, defensible-to-a-stakeholder" philosophy applied to a live agent platform instead of a UI; reach for it when the thing under review is agent behavior, not screens.