Skip to content

[web][a11y] A Slider enabled after its first frame has no aria-valuetext (its input reads "50") until its value changes #195215

Closed

Description

@cashmula

Steps to reproduce

  1. flutter create --platforms web --empty slider_repro && cd slider_repro
  2. Replace lib/main.dart with the code sample below. It has two sliders: A is enabled from the first frame, B starts disabled (onChanged: null) and is enabled by a button.
  3. flutter build web --release, serve build/web (for example python3 -m http.server 8765 in that folder) and open it in Chrome.
  4. Press "Enable B" (the app calls ensureSemantics(), so the semantics tree is already on).
  5. In DevTools, read the hidden range inputs:
[...document.querySelectorAll('flt-semantics-host input[type="range"]')]
  .map((e) => [e.getAttribute('aria-valuetext'), e.value, e.min, e.max])

Expected results

Slider B's input carries aria-valuetext="B within 5 km" (what semanticFormatterCallback returns) as soon as it is enabled, like slider A does from the first frame.

Actual results

Measured with Playwright on the release build:

aria-valuetext value min max
A, first frame A within 5 km 1 0 2
B, after enabling missing 50 empty empty

B's input exists only after it is enabled, and it never gets its attributes: no aria-valuetext, and the browser's default range value of 50 out of 0 to 100, which is all assistive technology has to announce. The attributes appear only after B's value changes once.

In our app the distance slider of a filter sheet starts disabled behind an "Anywhere" switch, so a screen-reader user who turns that switch off hears "50" instead of the distance.

Likely cause

From reading lib/web_ui/lib/src/engine/semantics/incrementable.dart (unchanged in this respect on master at f1a0549, 2026-10-02):

  • Enabling the slider gives its existing semantics node the increase and decrease actions, so a new SemanticIncrementable is created for a node whose value, increasedValue and decreasedValue were set in an earlier update.
  • _pendingResync starts as false, and none of those fields is dirty in that update, so _updateInputValues() returns early and never writes value, min, max or aria-valuetext to the new <input>.

#187217 (the fix for #186472, in 3.47.0) made update() call _updateInputValues() in every gesture mode, but this dirty check still skips a role created for an already-populated node. A possible fix, untested: start _pendingResync as true, so a role's first update always syncs the input.

Code sample

Code sample
import 'package:flutter/material.dart';
import 'package:flutter/semantics.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  SemanticsBinding.instance.ensureSemantics();
  runApp(const MaterialApp(home: Demo()));
}

class Demo extends StatefulWidget {
  const Demo({super.key});
  @override
  State<Demo> createState() => _DemoState();
}

class _DemoState extends State<Demo> {
  double a = 5;
  double b = 5;
  bool bEnabled = false;

  @override
  Widget build(BuildContext context) => Scaffold(
    body: Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        // Enabled from the first frame.
        Slider(
          min: 1,
          max: 20,
          value: a,
          semanticFormatterCallback: (v) => 'A within ${v.round()} km',
          onChanged: (v) => setState(() => a = v),
        ),
        // Starts disabled, enabled by the button below.
        Slider(
          min: 1,
          max: 20,
          value: b,
          semanticFormatterCallback: (v) => 'B within ${v.round()} km',
          onChanged: bEnabled ? (v) => setState(() => b = v) : null,
        ),
        ElevatedButton(
          onPressed: () => setState(() => bEnabled = true),
          child: const Text('Enable B'),
        ),
      ],
    ),
  );
}

Flutter Doctor output

Doctor output
$ flutter doctor
[✓] Flutter (Channel stable, 3.47.2, on macOS 27.0.1 26A434 darwin-arm64, locale en-GB)
[✓] Chrome - develop for the web

$ flutter --version
Flutter 3.47.2 • channel stable • https://github.com/flutter/flutter.git
Framework • revision d3b14c8769 (8 weeks ago) • 2026-08-26 16:07:51 -0700
Engine • hash 1cf1c4773fb941c4c74a7f8bb144a8837596c0f4 (revision a804b26164) (1 months ago) • 2026-08-26 18:46:13.000Z
Tools • Dart 3.13.2 • DevTools 2.60.0

Browser: Google Chrome 155.0.8059.85.

Activity

  1. suryaKommana2662 commented on Oct 26, 2026

    @suryaKommana2662
    Contributor

    @cashmula I was able to reproduce the issue on the web release build. After enabling slider B, its input is missing aria-valuetext, min, and max attributes, while slider A has the expected attributes. The missing attributes appear after changing slider B's value. Routing this to the accessibility team for further investigation.

    Flutter Doctor Output

    [✓] Flutter (Channel master, 3.50.0-1.0.pre-209, on macOS 27.0 26A428 darwin-arm64, locale en-IN) [1,804ms]
        • Flutter version 3.50.0-1.0.pre-209 on channel master at /Users/suryakommana/develop/flutter
        • Upstream repository https://github.com/flutter/flutter.git
        • Framework revision 7b0a985e54 (3 days ago), 2026-10-23 00:20:16 +0000
        • Engine revision 7b0a985e54
        • Dart version 3.15.0 (build 3.15.0-67.0.dev)
        • DevTools version 2.61.0
        • Feature flags: enable-web, enable-linux-desktop, enable-macos-desktop, enable-windows-desktop, enable-android, enable-ios, cli-animations, enable-native-assets,
          enable-record-use, enable-swift-package-manager, omit-legacy-version-file, enable-lldb-debugging, enable-uiscene-migration, enable-riscv64, enable-hcpp
    
    [✓] Android toolchain - develop for Android devices (Android SDK version 36.0.0) [2.3s]
        • Android SDK at /Users/suryakommana/Library/Android/sdk
        • Emulator version 37.1.11.0 (build_id 15917651) (CL:N/A)
        • Platform android-37.0, build-tools 36.0.0
        • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
          This is the JDK bundled with the latest Android Studio installation on this machine.
          To manually set the JDK path, use: `flutter config --jdk-dir="path/to/jdk"`.
        • Java version OpenJDK Runtime Environment (build 25.0.2+-15348964-b329.117)
        • All Android licenses accepted.
    
    [✓] Xcode - develop for iOS and macOS (Xcode 27.1) [2.0s]
        • Xcode at /Applications/Xcode.app/Contents/Developer
        • Build 27A9275
        • CocoaPods version 1.17.0
    
    [✓] Chrome - develop for the web [4ms]
        • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
    
    [✓] Connected device (2 available) [5.9s]
        • macOS (desktop) • macos  • darwin-arm64   • macOS 27.0 26A428 darwin-arm64
        • Chrome (web)    • chrome • web-javascript • Google Chrome 155.0.8059.85
    
    [✓] Network resources [633ms]
        • All expected network resources are available.
    
    • No issues found!
  2. added
    a: accessibilityAccessibility, e.g. VoiceOver or TalkBack. (aka a11y)
    has reproducible stepsThe issue has been confirmed reproducible and is ready to work on
    fyi-webFor the attention of Web platform team
    team-accessibilityOwned by Framework Accessibility team (i.e. responsible for accessibility code in flutter/flutter)
    and removed
    in triagePresently being triaged by the triage team
    on Oct 26, 2026
  3. flutter-zl commented on Oct 28, 2026

    @flutter-zl
    Contributor
    Reproduced on Chrome with a recent master build.
    
    Demo: https://flutter-demo-82-before.web.app
    
    1. Click "Read slider inputs". Only slider A has an input, with `aria-valuetext="A within 5 km"`, `min="0"`, `max="2"`.
    2. Click "Enable B", then "Read slider inputs" again.
    
    Slider B's input has no `aria-valuetext`, `value="50"`, and no `min` or `max`. Its attributes show up only after you drag it once.
    
    This is consistent with the analysis in the report: the new `SemanticIncrementable` is created for a node whose value fields are not dirty, so `_updateInputValues()` returns early on the first update.
    
  4. added
    P2Important issues not at the top of the work list
    triaged-webTriaged by Web platform team
    on Oct 28, 2026
  5. flutter-triage-bot commented on Oct 28, 2026

    @flutter-triage-bot

    The triaged-web label is irrelevant if there is no team-web label or fyi-web label.

  6. removed
    team-webOwned by Web platform team
    triaged-webTriaged by Web platform team
    team-accessibilityOwned by Framework Accessibility team (i.e. responsible for accessibility code in flutter/flutter)
    on Oct 28, 2026
  7. flutter-triage-bot commented on Oct 28, 2026

    @flutter-triage-bot

    Issue is assigned to multiple teams (web, accessibility). Please ensure the issue has only one team-* label at a time. Use fyi-* labels to have another team look at the issue without reassigning it.

  8. self-assigned this
    on Nov 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

P2Important issues not at the top of the work lista: accessibilityAccessibility, e.g. VoiceOver or TalkBack. (aka a11y)has reproducible stepsThe issue has been confirmed reproducible and is ready to work onteam-webOwned by Web platform teamtriaged-webTriaged by Web platform team

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions