Skip to content

Settings buttons cannot take keyboard focus, so a keyboard-only user cannot reach Save or Cancel #3028

Description

@saurabhav88

Tier: MEDIUM | Test: required (AppKit) | Modules: AppKit

What a user cannot do

No button on any Settings page can take keyboard focus. Someone who navigates with the
keyboard, or with an assistive technology that follows focus, can reach the text fields on a
page and nothing else. In a sheet that means Cancel, Save and Delete are unreachable: the only
key that works is Escape, which SettingsActionButton's shortcut: .cancelAction binds on the
Cancel button.

Measured, not inferred

Taken during #3018's Live UAT on 2026-09-17, against the dev build, with the accessibility API
rather than synthetic key presses (the app was NOT frontmost, so nothing was typed anywhere):
each control in the New snippet sheet had AXFocused set to true and then read back.

Control Role AXFocused after set
trigger field AXTextField true
expansion editor AXTextArea true
Today's date AXButton none
Time now AXButton none
Last copied AXButton none
Cancel AXButton none
Save AXButton none

A second, independent observation of the same fact: pressing Tab fourteen times with the sheet
frontmost left fourteen \t characters in the expansion editor and never moved focus, because
TextEditor consumes Tab as a character and no sibling control is a focus candidate.

Where it comes from

SettingsActionButton (Sources/EnviousWisprAppKit/Views/Settings/SettingsComponents.swift)
applies .buttonStyle(.plain) to its whole body. That is what makes every Settings button a
non-focusable control. It is used at 66 call sites across 25 Settings files
(/usr/bin/grep -rn "SettingsActionButton(" Sources/EnviousWisprAppKit/ | wc -l = 66 at
0c455d7c), so this is one root cause with an app-wide blast radius, not a per-sheet defect.

Why it is filed rather than fixed inside #3018

#3018 added three of the affected buttons; the other 63 predate it, including the Cancel and
Save that make a sheet usable at all. A fix changes the focus ring, the focus order and the
keyboard behaviour of every Settings page, which is its own plan, its own review and its own
Live UAT. Founder's call on 2026-09-17: ship #3018, file this.

Scope to settle when this is planned

  • Whether the fix is a focusable button style or a custom .focusable() + .onKeyPress
    treatment, and what the focus ring looks like against the dark Settings surfaces.
  • Focus ORDER inside a sheet, including how a TextEditor is escaped (Tab is consumed by the
    text view; Ctrl+Tab is the AppKit convention and was not tested).
  • Whether Save should also carry .defaultAction, which today it does not.
  • The regression test. The Live UAT instrument above is the right shape for it: it needs no
    synthetic keystrokes and no frontmost app, so it can assert focusability per control.

Related: #3018 (added three of the buttons), #2447 (the destructive-role finding on this same
type).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2-mediumMedium prioritybugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions