Skip to content

[Google3 Bug][A11Y]: Voiceover focus traversal breaks if a button's state changes to include an icon #172489

@brynn

Description

@brynn

###Help us understand the severity of this issue

  • causing severe production issues e.g. malfunctions or data loss
  • blocking next binary release
  • blocking a client feature launch within a quarter
  • nice-to-have but does not block a launch within the next quarter

Steps to reproduce

  1. Using a screenreader such as Voiceover, focus on the first button
  2. Click the first button using the screenreader
  3. Observe that the focus jumps forward to the next button
  4. Click the second button using the screenreader
  5. Observe that the focus jumps backwards to the first button

Expected results

When clicking a button using a screenreader, the focus should remain on that button.

Actual results

The focus jumps forward or backwards if a button's state changes to include an icon.

Code sample

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

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(body: Center(child: ButtonIconExample())),
    );
  }
}

class ButtonIconExample extends StatefulWidget {
  const ButtonIconExample({super.key});

  @override
  State<StatefulWidget> createState() => ButtonIconExampleState();
}

class ButtonIconExampleState extends State<ButtonIconExample> {
  bool toggled1 = false;
  bool toggled2 = false;

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Card(
        color: Colors.blue,
        child: SizedBox(
          width: 500,
          height: 100,
          child: Row(
            children: [
              OutlinedButton.icon(
                label: Text('test button 1'),
                onPressed: () => setState(() => toggled1 = !toggled1),
                icon: toggled1 ? Icon(Icons.favorite) : null,
              ),
              OutlinedButton.icon(
                label: Text('test button 2'),
                onPressed: () => setState(() => toggled2 = !toggled2),
                icon: toggled2 ? Icon(Icons.favorite) : null,
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Screenshots or Video

Screenshots / Video demonstration
Screen.Recording.2025-07-21.at.4.32.59.PM.mov

Logs

Logs
[Paste your logs here]

Flutter Doctor output

Doctor output
[Paste your output here]

Metadata

Metadata

Assignees

Labels

P1High-priority issues at the top of the work lista: accessibilityAccessibility, e.g. VoiceOver or TalkBack. (aka a11y)customer: googleVarious Google teamscustomer: quake (g3)f: focusFocus traversal, gaining or losing focusfound in release: 3.32Found to occur in 3.32found in release: 3.33Found to occur in 3.33frameworkflutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onr: fixedIssue is closed as already fixed in a newer versionteam-iosOwned by iOS platform teamtriaged-iosTriaged by iOS platform team

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions