A11Y: Composer stack and discard buttons are invisible keyboard Tab stops #819

Open
opened 2026-10-02 13:16:22 +00:00 by kayg · 3 comments
Owner

Context

Source accessibility review of origin/dev at c4a61e8cf090170f35b1bed3350d9de20c83ecd5, job rev-a11y, assigned #427. Composer supplies keyboard alternatives to its stack/discard gestures, but those alternatives have no visible focus.

Evidence

  • apps/web/src/lib/composer/Composer.svelte:1847–1850 declares Stack draft and Discard draft as native buttons with class="sr-only". They have no negative tabindex. The comment says they are reachable by Tab.
  • apps/web/src/calternal-app.css:260–270 clips .sr-only to a 1 px box with clip: rect(0, 0, 0, 0) and overflow hidden.
  • Neither the utility nor Composer supplies a focus reveal. The global focus outline cannot make the clipped button or its label visible.

A keyboard User can therefore land on a control whose purpose and focus are invisible. This fails WCAG 2.4.7 Focus Visible. The buttons remain useful to a screen reader; removing them without an equivalent reachable action would lose that access.

Expected and exact fix

Provide visible, named keyboard alternatives for both actions. Reuse a shared focus-reveal utility or the existing visible Composer action surface. If a focus-reveal utility is used, reveal the label and full focus ring while the button has keyboard focus, and keep the revealed control in view. Preserve the action guards and draft recovery behavior. Do not change keyboard motion durations.

Test idea

Open Composer, type a real draft, and Tab through its controls. Stack draft and Discard draft must each have a visible label and focus indicator when reached. Activate each with Enter and Space, check its result, and check the existing recovery path after discard. Test the revealed layout at 390, 820 and 1440 px in light/dark with macOS platform emulation. A focused-clipping assertion must fail for the current implementation.

Duplicate search

Searches: "Stack draft" (no results), composer keyboard, and #308. #308 concerns duplicate sr-only definitions; #658 concerns ring styling. Neither tracks these clipped actionable Tab stops. One issue is filed for the Composer family.

# Context Source accessibility review of `origin/dev` at `c4a61e8cf090170f35b1bed3350d9de20c83ecd5`, job rev-a11y, assigned #427. Composer supplies keyboard alternatives to its stack/discard gestures, but those alternatives have no visible focus. # Evidence - `apps/web/src/lib/composer/Composer.svelte:1847–1850` declares Stack draft and Discard draft as native buttons with `class="sr-only"`. They have no negative tabindex. The comment says they are reachable by Tab. - `apps/web/src/calternal-app.css:260–270` clips `.sr-only` to a 1 px box with `clip: rect(0, 0, 0, 0)` and overflow hidden. - Neither the utility nor Composer supplies a focus reveal. The global focus outline cannot make the clipped button or its label visible. A keyboard User can therefore land on a control whose purpose and focus are invisible. This fails WCAG 2.4.7 Focus Visible. The buttons remain useful to a screen reader; removing them without an equivalent reachable action would lose that access. # Expected and exact fix Provide visible, named keyboard alternatives for both actions. Reuse a shared focus-reveal utility or the existing visible Composer action surface. If a focus-reveal utility is used, reveal the label and full focus ring while the button has keyboard focus, and keep the revealed control in view. Preserve the action guards and draft recovery behavior. Do not change keyboard motion durations. # Test idea Open Composer, type a real draft, and Tab through its controls. Stack draft and Discard draft must each have a visible label and focus indicator when reached. Activate each with Enter and Space, check its result, and check the existing recovery path after discard. Test the revealed layout at 390, 820 and 1440 px in light/dark with macOS platform emulation. A focused-clipping assertion must fail for the current implementation. # Duplicate search Searches: `"Stack draft"` (no results), `composer keyboard`, and #308. #308 concerns duplicate sr-only definitions; #658 concerns ring styling. Neither tracks these clipped actionable Tab stops. One issue is filed for the Composer family.
Author
Owner

Additional source check: Stack draft and Discard draft are native tab stops styled with .sr-only; the 1 px clipping keeps the global focus ring and label out of view. I am adding a visible-focus keyboard check and preserving the discard Undo action.

Additional source check: Stack draft and Discard draft are native tab stops styled with `.sr-only`; the 1 px clipping keeps the global focus ring and label out of view. I am adding a visible-focus keyboard check and preserving the discard Undo action.
Author
Owner

Started work on job/undo-a11y-a11y, based on 9281e63b0164fd0297d959f37eb0008bfa0aa4d3. Scope: issues #740, #741, #744, #745, #819 and #820. I am reproducing each reported behavior with a regression test before changing implementation.

Started work on `job/undo-a11y-a11y`, based on `9281e63b0164fd0297d959f37eb0008bfa0aa4d3`. Scope: issues #740, #741, #744, #745, #819 and #820. I am reproducing each reported behavior with a regression test before changing implementation.
Author
Owner

Finding #819: Composer's Stack draft and Discard draft native buttons were Tab stops but remained clipped to the shared 1 px .sr-only box when focused. The visible focus ring could not show either label. The fix overrides that clipping only for keyboard focus and lets the expanded button participate in Composer scroll flow. A production browser regression now Tabs to both controls, checks their full bounding boxes and focus ring, activates them with Space and Enter, and verifies Undo restores the discarded draft. The browser run awaits the shared server binary.

Finding #819: Composer's Stack draft and Discard draft native buttons were Tab stops but remained clipped to the shared 1 px `.sr-only` box when focused. The visible focus ring could not show either label. The fix overrides that clipping only for keyboard focus and lets the expanded button participate in Composer scroll flow. A production browser regression now Tabs to both controls, checks their full bounding boxes and focus ring, activates them with Space and Enter, and verifies Undo restores the discarded draft. The browser run awaits the shared server binary.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal#819
No description provided.