Skip to content

checkbox: Name an unlabeled checkbox after its id - #3440

Open
bytezer wants to merge 1 commit into
longbridge:mainfrom
bytezer:checkbox-accessible-name-fallback
Open

bytezer wants to merge 1 commit into
longbridge:mainfrom
bytezer:checkbox-accessible-name-fallback

Conversation

@bytezer

@bytezer bytezer commented Oct 11, 2026

Copy link
Copy Markdown

Fixes #3381.

What

A Checkbox built without .label(...) or .accessibility_label(...)
reported an empty accessible name, so UIA (and VoiceOver) consumers could
not tell two unnamed checkboxes in a list apart. The checked state was
already reported correctly — only the name was missing.

How

Checkbox::render now resolves the announced name in one place,
accessible_name: an explicit accessibility_label wins, then the
visible label, and finally the element id. The id fallback gives every
control a distinguishing, non-empty name, which is the first suggestion
in the issue (and mirrors how Button derives its name from its label).

No public API changed: accessible_name is private and the builder API
is untouched.

Tests

  • an_unlabeled_checkbox_is_named_after_its_id covers the id fallback,
    an explicit name, and the visible label.
  • cargo test -p gpui-component — 657 lib tests + 48 integration tests, all green.
  • cargo clippy -p gpui-component --all-targets -- --deny warnings
  • cargo fmt --check

AI assistance

The change and its test were drafted with an AI coding agent, then
reviewed, compiled and tested locally before submitting.

A checkbox rendered without a label and without an explicit
accessibility_label exposed an empty accessible name, so UIA
consumers could not tell two of them apart in a list.

Resolve the announced name as: the explicit accessibility_label, then
the visible label, then the element id. The id fallback keeps every
checkbox addressable and distinguishable.

@huacnlee huacnlee left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for picking up #3381 — the missing name is a real gap. I don't think the element id is the right fallback, though.

1. It overrides names that already work. A checkbox may carry its text as children instead of .label(...) (has_content counts children). With no explicit label, AccessKit names Role::CheckBox from its descendant Role::Label nodes (accesskit_consumer::Node::labelled_by → LabelledBy::FromDescendants), and GPUI text elements are Role::Label. So today

Checkbox::new("agree").child("I agree to the terms")

is announced as "I agree to the terms". With this PR the label is always set explicitly, so it becomes "agree".

2. An id is not a name. Ids are developer identifiers: unlocalized, and Integer, NamedInteger and Uuid ids are read out as "3", "row-5" or a UUID. It also hides the problem from audit tools: Accessibility Insights stops flagging the missing name while users still hear nothing meaningful. Our own setting/fields/bool.rs shows it: every bool setting is Checkbox::new("check"), so they would all be announced "check", still indistinguishable. Button, Switch and Radio don't fall back to the id either.

3. The test only covers the private helper, not the name in the AccessKit tree, so it can't catch (1).

Suggested direction (the issue's second option):

  • Drop the id fallback, and document on Checkbox::accessibility_label (and the en/zh-CN docs) that a checkbox without visible text must set it.
  • Fix the internal unnamed usage: pass the setting's title as accessibility_label for the Checkbox/Switch in setting/fields/bool.rs.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Checkbox: empty accessible name (UIA Name) when no label is provided

2 participants