From 57522c42e35908a8ae92b59ffc5a04b964f7fe3d Mon Sep 17 00:00:00 2001 From: Matt Van Horn Date: Tue, 5 May 2026 04:07:04 -0700 Subject: [PATCH] Restore visible focus indicator for keyboard tab navigation Closes #6065. The blanket `:focus` rule in `public/assets/css/main.css` strips `outline` and `box-shadow` from anchors, inputs, textareas, buttons, and the Bootstrap `.btn` family. With both indicators gone, keyboard users lose all visual feedback while tabbing through forms (the case-contact form was called out specifically) -- a serious WCAG 2.4.7 "Focus Visible" failure for an app whose users include CASA volunteers and supervisors who rely on keyboard navigation. Scope the existing reset to `:focus:not(:focus-visible)` so mouse click-focus stays clean, and add a sibling `:focus-visible` rule that draws a 2px outline in the project blue (#4a6cf7) with 2px offset. Browser support for `:focus-visible` is universal at this point (Chrome 86+, Firefox 85+, Safari 15.4+); pre-`:focus-visible` browsers silently fall back to the still-present `:focus` rule. The `.btn.focus` and `.btn:active`/`.btn.active` selectors are left on the reset rule because they represent intentional Bootstrap state classes, not the `:focus` pseudo-class -- they should not gain a focus ring just for being active. Other `outline: none` rules (`.select-style-{1,2,3} .select-position select:focus` at lines 1226/1286/1340) are scoped to selects that get a `border-color` change as their focus indicator, so they still communicate focus and are out of scope here. Tested locally: tabbing through `/cases/.../case_contacts/new` now shows the blue outline on every input and the submit button; mouse clicks do not. --- public/assets/css/main.css | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/public/assets/css/main.css b/public/assets/css/main.css index 57b314ce3a..3e1f3810bd 100644 --- a/public/assets/css/main.css +++ b/public/assets/css/main.css @@ -20,11 +20,11 @@ body { -moz-box-sizing: border-box; box-sizing: border-box; } -a:focus, -input:focus, -textarea:focus, -button:focus, -.btn:focus, +a:focus:not(:focus-visible), +input:focus:not(:focus-visible), +textarea:focus:not(:focus-visible), +button:focus:not(:focus-visible), +.btn:focus:not(:focus-visible), .btn.focus, .btn:not(:disabled):not(.disabled).active, .btn:not(:disabled):not(.disabled):active { @@ -34,6 +34,14 @@ button:focus, -moz-box-shadow: none; box-shadow: none; } +a:focus-visible, +input:focus-visible, +textarea:focus-visible, +button:focus-visible, +.btn:focus-visible { + outline: 2px solid #4a6cf7; + outline-offset: 2px; } + a:hover { color: #4a6cf7; }