Skip to content

[web] Propagate aria-label to inner slider input - #192964

Merged
auto-submit[bot] merged 10 commits into
flutter:masterfrom
kevmoo:web-a11y-pr2-input-aria-label
Oct 3, 2026
Merged

auto-submit[bot] merged 10 commits into
flutter:masterfrom
kevmoo:web-a11y-pr2-input-aria-label

Conversation

@kevmoo

@kevmoo kevmoo commented Sep 18, 2026 •

Copy link
Copy Markdown
Contributor

On Flutter Web, SemanticIncrementable (role="slider") renders an outer <flt-semantics> container alongside an inner <input type="range" role="slider">. Previously, AriaLabelRepresentation set aria-label exclusively on the outer <flt-semantics> wrapper (role="none" when active), leaving the interactive <input role="slider"> element without an accessible name in the browser's accessibility tree (name: "" in Chrome Accessibility.getFullAXTree and "50%, slider" in VoiceOver).

This change:

  1. Propagates semanticsObject.label to the inner <input role="slider"> element's aria-label attribute in SemanticIncrementable.update(), removing it when the label becomes empty.
  2. Tracks _previousLabel in AriaLabelRepresentation so stale aria-label attributes are cleaned up when a label is cleared.
  3. Adds unit tests in semantics_test.dart (_testIncrementables()) verifying aria-label propagation and cleanup on <input role="slider">.

Fixes http://b/463248173

Pre-launch Checklist

  • I read the [Contributor Guide] and followed the process outlined there for submitting PRs.
  • I read the [Tree Hygiene] wiki page, which explains my responsibilities.
  • I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement].
  • I signed the [CLA].
  • I listed at least one issue that this PR fixes in the description above.
  • I updated/added relevant documentation (doc comments with ///).
  • I added new tests to check the change I am making, or this PR is [test-exempt].
  • I followed the [breaking change policy] and added [Data Driven Fixes] where supported.
  • All existing and new tests are passing.

- Mirror computed aria-label onto SemanticIncrementable inner <input type='range' role='slider'> (b/463248173).

- Always set aria-label on SemanticTextField editableElement and fall back to hint when label is empty (b/463281931, Fixes flutter#172206, Fixes flutter#192618).

- Assign _previousLabel in AriaLabelRepresentation.update.
@github-actions github-actions Bot added a: text input Entering text in a text field or keyboard related problems engine flutter/engine related. See also e: labels. a: accessibility Accessibility, e.g. VoiceOver or TalkBack. (aka a11y) platform-web Web applications specifically team-web Owned by Web platform team labels Sep 18, 2026
@kevmoo kevmoo changed the title fix(web_ui): propagate aria-label to inner slider and text field inputs [web] Propagate aria-label to inner slider and text field inputs Sep 18, 2026
@kevmoo
kevmoo marked this pull request as ready for review September 18, 2026 04:06

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request updates the web semantics implementation to improve accessibility. Specifically, it allows SemanticTextField to fall back to using its hint as the aria-label when the primary label is empty, and prevents duplicate screen reader announcements by only setting aria-description when both a non-empty label and hint are present. It also updates AriaLabelRepresentation to correctly track and clean up its previous label state, and synchronizes aria-label attributes in SemanticIncrementable. The review feedback suggests using trim().isNotEmpty in SemanticIncrementable to prevent setting whitespace-only labels and maintain consistency with the text field changes.

@flutter-zl flutter-zl added the CICD Run CI/CD label Sep 23, 2026
@flutter-zl
flutter-zl self-requested a review September 23, 2026 17:50
@flutter-dashboard

Copy link
Copy Markdown

CI had a failure that stopped further tests from running. We need to investigate to determine the root cause.

SHA at time of execution: b6ab1dc.

Possible causes:

  • Configuration Changes: The .ci.yaml file might have been modified between the creation of this pull request and the start of this test run. This can lead to ci yaml validation errors.
  • Infrastructure Issues: Problems with the CI environment itself (e.g., quota) could have caused the failure.

A blank commit, or merging to head, will be required to resume running CI for this PR.

Error Details:

FormatException: ERROR: Mac_arm64_ios basic_material_app_ios__compile is a new builder added. it needs to be marked bringup: true
If ci.yaml wasn't changed, try `git fetch upstream && git merge upstream/master`



Stack trace:

#0      CiYaml._validate (package:cocoon_service/src/model/ci_yaml/ci_yaml.dart:395:7)
#1      new CiYaml (package:cocoon_service/src/model/ci_yaml/ci_yaml.dart:128:7)
#2      new CiYamlSet (package:cocoon_service/src/model/ci_yaml/ci_yaml.dart:48:23)
#3      CiYamlFetcher._getCiYaml (package:cocoon_service/src/service/scheduler/ci_yaml_fetcher.dart:124:12)
<asynchronous suspension>
#4      Scheduler.getPresubmitTargets (package:cocoon_service/src/service/scheduler.dart:1064:20)
<asynchronous suspension>
#5      Scheduler._getTestsForStage (package:cocoon_service/src/service/scheduler.dart:1367:14)
<asynchronous suspension>
#6      Scheduler._runCiTestingStage (package:cocoon_service/src/service/scheduler.dart:1408:30)
<asynchronous suspension>
#7      Scheduler.proceedToCiTestingStage (package:cocoon_service/src/service/scheduler.dart:1517:7)
<asynchronous suspension>
#8      Scheduler._closeSuccessfulEngineBuildStage (package:cocoon_service/src/service/scheduler.dart:1312:5)
<asynchronous suspension>
#9      Scheduler.processCheckRunCompleted (package:cocoon_service/src/service/scheduler.dart:1253:11)
<asynchronous suspension>
#10     PresubmitSubscription._processBuild (package:cocoon_service/src/request_handlers/presubmit_subscription.dart:228:7)
<asynchronous suspension>
#11     PresubmitSubscription.post (package:cocoon_service/src/request_handlers/presubmit_subscription.dart:119:5)
<asynchronous suspension>
#12     RequestHandler.service (package:cocoon_service/src/request_handling/request_handler.dart:42:20)
<asynchronous suspension>
#13     SubscriptionHandler.service (package:cocoon_service/src/request_handling/subscription_handler.dart:134:5)
<asynchronous suspension>
#14     createServer.<anonymous closure> (package:cocoon_service/server.dart:462:7)
<asynchronous suspension>
#15     main.<anonymous closure>.<anonymous closure> (file:///app/app_dart/bin/gae_server.dart:192:9)
<asynchronous suspension>

@chunhtai

Copy link
Copy Markdown
Contributor

Does this fix #192618 ? The issue is about buttons missing aria labels

@kevmoo

kevmoo commented Sep 23, 2026

Copy link
Copy Markdown
Contributor Author

Good catch @chunhtai! #192618 is specifically about SemanticButton (LabelRepresentation.domText vs aria-label) and DropdownButtonFormField2 wrapped in Semantics(container: true), whereas this PR only updates <input> aria-label propagation for SemanticSlider (Incrementable) and SemanticTextField (#172206). I've removed Fixes https://github.com/flutter/flutter/issues/192618 from the PR description so it isn't auto-closed when this lands.

@flutter-zl flutter-zl left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for this! I tested it with two demos, the same app on master and on this PR:

The slider fix works. On master, VoiceOver reads the slider as "50%, slider". With this PR, it reads "50%, Volume, slider".

The text field part needs changes:

  1. It doesn't help hintText fields. In the demo, a hintText field still has no name after typing, in both builds.
  2. It doesn't fix #172206. The reporter still gets two inputs, "Login_email" and "Email". The DOM is the same before and after.
  3. The description doesn't match the code. There is no _updateLabels, and master doesn't remove the label when a field loses focus.

REQUEST CHANGES. I'd land the slider fix on its own and rework the text field part.

@flutter-zl
flutter-zl requested a review from chunhtai September 24, 2026 17:11
- Revert SemanticTextField changes so InputDecorator.hintText (which is
  dropped from the semantics tree via AnimatedOpacity(opacity: 0.0) when
  !isEmpty) can be addressed in the framework separately.
- Add unit test in _testIncrementables() verifying aria-label propagation
  and cleanup on the inner <input role="slider"> element.
@kevmoo kevmoo changed the title [web] Propagate aria-label to inner slider and text field inputs [web] Propagate aria-label to inner slider input Sep 25, 2026
@kevmoo

kevmoo commented Sep 25, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for testing this with VoiceOver and catching the InputDecoration(hintText: ...) behavior after typing, @flutter-zl!

Root cause on the TextField side: in packages/flutter/lib/src/material/input_decorator.dart (_InputDecoratorState.build), InputDecoration.hintText is rendered as a Text(hintText!) child inside an AnimatedOpacity(opacity: showHint ? 1.0 : 0.0) where showHint = isEmpty && !_hasInlineLabel. Once the user types into the field (isEmpty == false), AnimatedOpacity(opacity: 0.0) drops the hint widget from the semantics tree entirely—leaving both semanticsObject.label and semanticsObject.hint empty in web_ui.

As you suggested, I've scoped this PR strictly to the verified Slider (SemanticIncrementable) aria-label fix (b/463248173), reverted the SemanticTextField changes, and added a unit test in _testIncrementables() covering aria-label propagation and cleanup on <input role="slider">. We'll follow up on InputDecorator's semantics preservation when !isEmpty in a separate framework PR. Ready for another look!

@kevmoo
kevmoo requested a review from flutter-zl September 25, 2026 03:24
@github-actions github-actions Bot removed the a: text input Entering text in a text field or keyboard related problems label Sep 25, 2026
flutter-zl
flutter-zl previously approved these changes Sep 25, 2026

@flutter-zl flutter-zl left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for scoping this down! The slider fix and the new test look good.

With VoiceOver in Chrome:
- master: "Volume, group ... 50%, slider"
- this PR: "Volume, group ... 50%, Volume, slider"

Before: https://flutter-demo-66-before.web.app/

After: https://flutter-demo-66-after.web.app/

@flutter-zl flutter-zl added the autosubmit Merge PR when tree becomes green via auto submit App label Sep 25, 2026
@auto-submit auto-submit Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Sep 25, 2026
@auto-submit

auto-submit Bot commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

autosubmit label was removed for flutter/flutter/192964, because - The status or check suite Dashboard Checks has failed. Please fix the issues identified (or deflake) before re-applying this label.

@kevmoo kevmoo added the autosubmit Merge PR when tree becomes green via auto submit App label Oct 2, 2026
@auto-submit
auto-submit Bot added this pull request to the merge queue Oct 2, 2026
Merged via the queue into flutter:master with commit f1a0549 Oct 3, 2026
33 of 34 checks passed
@flutter-dashboard flutter-dashboard Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Oct 3, 2026
@kevmoo
kevmoo deleted the web-a11y-pr2-input-aria-label branch October 5, 2026 16:55
suryaKommana2662 pushed a commit to suryaKommana2662/flutter that referenced this pull request Oct 29, 2026
On Flutter Web, `SemanticIncrementable` (`role="slider"`) renders an
outer `<flt-semantics>` container alongside an inner `<input
type="range" role="slider">`. Previously, `AriaLabelRepresentation` set
`aria-label` exclusively on the outer `<flt-semantics>` wrapper
(`role="none"` when active), leaving the interactive `<input
role="slider">` element without an accessible name in the browser's
accessibility tree (`name: ""` in Chrome `Accessibility.getFullAXTree`
and `"50%, slider"` in VoiceOver).

This change:
1. Propagates `semanticsObject.label` to the inner `<input
role="slider">` element's `aria-label` attribute in
`SemanticIncrementable.update()`, removing it when the label becomes
empty.
2. Tracks `_previousLabel` in `AriaLabelRepresentation` so stale
`aria-label` attributes are cleaned up when a label is cleared.
3. Adds unit tests in `semantics_test.dart` (`_testIncrementables()`)
verifying `aria-label` propagation and cleanup on `<input
role="slider">`.

Fixes http://b/463248173

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

---------

Co-authored-by: zhongliugo <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a: accessibility Accessibility, e.g. VoiceOver or TalkBack. (aka a11y) CICD Run CI/CD engine flutter/engine related. See also e: labels. platform-web Web applications specifically team-web Owned by Web platform team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants