fix(a11y): sweep focus:ring-primary/50 to full-opacity ring for WCAG AA contrast (#1218)#1265
Conversation
…AA contrast (#1218) Uniform mechanical sweep of all 18 remaining focus:ring-primary/50 usages (6 board components incl. the canonical ColumnEditModal) to the full-opacity focus:ring-primary treatment PR #1216 established on BoardSettingsModal: 50% primary on dark bg-surface-container-high (#2a2a2a) is ~2.8:1, below the WCAG 2.1 AA 3:1 minimum for UI component indicators.
There was a problem hiding this comment.
Code Review
This pull request updates the focus ring styling across multiple Vue components in the board directory, including ColumnEditModal, FilterPanel, LabelManagerModal, CardModalComments, CardModalForm, and CardModalLabels. Specifically, it replaces the semi-transparent focus ring class focus:ring-primary/50 with the solid focus:ring-primary class on various input fields, checkboxes, textareas, and select elements to ensure a more prominent focus state. There are no review comments, so I have no feedback to provide.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
There was a problem hiding this comment.
Pull request overview
This PR improves keyboard focus visibility across board-related modals/panels by replacing low-contrast focus:ring-primary/50 focus ring styling with full-opacity focus:ring-primary, aligning focus indicators with WCAG AA contrast expectations on dark surfaces.
Changes:
- Replaced
focus:ring-primary/50withfocus:ring-primaryin 6 board components (18 occurrences). - Kept changes strictly to class strings (no behavioral/layout changes) to minimize regression risk.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| frontend/taskdeck-web/src/components/board/ColumnEditModal.vue | Updates text/number inputs and checkbox focus ring to full-opacity primary. |
| frontend/taskdeck-web/src/components/board/FilterPanel.vue | Updates search/select and checkbox focus ring to full-opacity primary. |
| frontend/taskdeck-web/src/components/board/LabelManagerModal.vue | Updates label name/color inputs focus ring to full-opacity primary. |
| frontend/taskdeck-web/src/components/board/card-modal/CardModalForm.vue | Updates card form inputs/textarea/date/checkbox focus ring to full-opacity primary. |
| frontend/taskdeck-web/src/components/board/card-modal/CardModalComments.vue | Updates comment/reply textareas focus ring to full-opacity primary. |
| frontend/taskdeck-web/src/components/board/card-modal/CardModalLabels.vue | Updates label checkbox focus ring to full-opacity primary. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…abel state ring) to full opacity (#1218 review)
…5 checkboxes (#1218 review) Without a ring-width utility (focus:ring-2) and with no forms plugin, focus:ring-primary only sets --tw-ring-color and paints nothing. Checkbox keyboard focus is indicated by the global *:focus-visible box-shadow rule (style.css) at 4.52:1 — already WCAG AA compliant.
Adversarial Code ReviewTwo independent review agents (a11y/theme-correctness lens + sweep-completeness/regression lens), both empirically grounded (compiled the actual Tailwind v4 output; computed WCAG relative-luminance contrast against the real theme tokens). CRITICAL
HIGH
MEDIUM
LOW
Bot Comments Addressed
Verified-sound (could not refute)
Summary0 CRITICAL / 0 HIGH / 2 MEDIUM / 2 LOW. Nothing merge-blocking; both MEDIUMs fixed in-PR (see follow-up comment). |
Adversarial Review — Fixes Applied
Net effect of the PR after fixes: 13 rendered focus rings lifted 3.0–3.5:1 → 8.4–10.1:1; 1 rendered state ring lifted 3.44:1 → full opacity; 6 dead classes removed; 0 All findings addressed. CI status: PENDING (running on |
|
Post-merge record correction: the PR body prose said 'removes 6 compile-proven dead |
* docs: STATUS post-merge sync — #1241 (#1263) + #1218 (#1265) shipped * docs: masterplan delivery log — 2026-07-02 security + a11y slices (#1263, #1265) * docs: MEDIUM correct dead-class count 6->5 + precise 19-site arithmetic + Codex-coverage phrasing (#1268 review) * docs: LOW separate shipped vs still-open phrasing per Gemini (#1268)
Closes #1218.
What
Sweeps every remaining
ring-primary/50usage (18focus:+ 1 selected-state; 0 left repo-wide) to the full-opacity treatment PR #1216 established onBoardSettingsModal, and removes 5 compile-proven deadfocus:ring-primaryclasses from checkboxes (no ring-width utility + no forms plugin ⇒ the class never painted; checkbox focus is compliantly indicated by the global*:focus-visiblerule at 4.52:1).Why
Issue #1218: a 50%-opacity primary ring on the dark surfaces is marginal — adversarial review of this PR computed 3.00–3.49:1 against the actual adjacent surfaces (the issue's '~2.8:1' was overstated, but the treatment was at/near the WCAG 2.1 AA 3:1 floor for UI component indicators). Full opacity lifts the rendered indicators to 8.41–10.07:1 on every adjacent surface, verified across all shipped themes (ring color + surfaces are build-time-static Tailwind hex; theme switches only remap
--td-*/--papervars).Files (6, all in
components/board/)ColumnEditModal.vue(canonical token pattern) — 2 rings full-opacity, 1 dead class removedFilterPanel.vue— 2 rings, 2 dead classes removedLabelManagerModal.vue— 2 ringscard-modal/CardModalForm.vue— 4 rings, 1 dead class removedcard-modal/CardModalComments.vue— 3 ringscard-modal/CardModalLabels.vue— 1 selected-state ring full-opacity, 1 dead class removedReview
Two independent adversarial reviews (a11y/theme lens + completeness/regression lens) posted below; all findings of every severity fixed in-PR or tracked (#1266).
Verification
grep -rn "ring-primary/50" frontend/taskdeck-web/src→ 0 hits (incl. non-focus usages)npm run typecheck→ 0 errors;npm run lint→ 0 errors (6 pre-existing warnings)