Skip to content

A11y: Dropdowns have accessibility focus issues #40101

Closed

Description

@andywolff

Internal: b/140831334

If you have a dropdown (DropdownButton and DropdownMenuItems) below a Navigator in a MaterialApp, it breaks the screenreader focus behavior.

The problem is that when you activate the dropdown button, focus gets lost instead of going to the selected item in the popup. Sometimes it works properly the first time you open the popup, but not subsequent times. One strange thing I noticed (TalkBack only) was that if you navigate backwards three times in this state, it will successfully focus on the last element, but navigating forwards from this state never focuses on anything. Also, when you select an item and the popup closes, focus gets lost instead of returning to the button.

If the dropdown does not have a Navigator in its ancestry, it doesn't have this problem.

Our app does have a page where the dropdown focus works correctly even though it has a Navigator in the tree above the dropdown. This gives me hope that there may be some kind of workaround for the issue. However, I haven't been able to isolate what makes this different from the repro case below because the app's tree has many layers.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Navigator(
        onGenerateRoute: (_) {
          return MaterialPageRoute(
            builder: (context) {
              return Scaffold(
                body: SafeArea(
                  child: DropdownButton(
                    value: "foo",
                    items: [
                      DropdownMenuItem(value: "foo", child: Text("Foo"),),
                      DropdownMenuItem(value: "bar", child: Text("Bar"),),
                    ],
                    onChanged: (_) {},
                  ),
                ),
              );
            },
          );
        },
      ),
    );
  }
}

Tested on both Android and iOS. Issue is present on both.

Activity

  1. added
    p: material_uimaterial_ui package in flutter/packages
    frameworkflutter/packages/flutter repository. See also f: labels.
    on Sep 10, 2019
  2. HansMuller commented on Sep 10, 2019

    @HansMuller
    Contributor
  3. gspencergoog commented on Sep 10, 2019

    @gspencergoog
    Contributor

    I assume that when you're referring to focus navigation here, you are referring accessibility focus within TalkBack/VoiceOver, correct, and not to regular input focus?

  4. andywolff commented on Sep 10, 2019

    @andywolff
    ContributorAuthor

    Yes, accessibility focus

  5. jkurtw commented on Sep 10, 2019

    @jkurtw

    Internal: b/140831334

  6. changed the title [-]A11y: Dropdowns with a nested Navigator have focus issues[/-] [+]A11y: Dropdowns with a nested Navigator have accessibility focus issues[/+] on Sep 11, 2019
  7. self-assigned this
    on Sep 11, 2019
  8. gspencergoog commented on Sep 11, 2019

    @gspencergoog
    Contributor

    In investigating this, it appears to be a larger problem: the dropdown button doesn't actually support any kind of focus properly yet (it doesn't yet manage a focus node), so once the selection is made, the input focus returns to another control.

    I'll work on getting that to work properly, and I think that will also fix the a11y issue.

    Also, the work I have in #40166 should also help, since dropdowns use their own kind of Route.

  9. 7 remaining items

  10. Norbert515 commented on Sep 21, 2019

    @Norbert515
    Contributor

    This issue also affects shortcuts on desktop. The new Shortcuts widget relies on focus. When pressing a DropDownButton a new route is pushed and the focus to the Shortcuts is lost, thus shortcuts do not work anymore.
    Looking forward to the PR

  11. gspencergoog commented on Sep 23, 2019

    @gspencergoog
    Contributor

    Yes, that's also a known issue, but that's not related to this one, since that is input focus, not accessibility focus. In that case, it's just because we're not done enabling all widgets with focus handling.

  12. gspencergoog commented on Sep 24, 2019

    @gspencergoog
    Contributor

    OK, I think I've got a fix for this problem. It will land in two parts: one an engine fix: flutter-team-archive/engine#12410, and another that changes the behavior for dropdown widgets and popups (and other widgets) to set the input focus bit in the semantics of components that have the "primary focus", and also add regular (non-a11y) focus support to dropdowns and popups.

  13. Hixie commented on Oct 8, 2019

    @Hixie
    Contributor

    update: being worked on; there was a performance regression that we're tracking down before we can commit this. Thank you for your patience.

  14. added a commit that references this issue on Oct 10, 2019
    ce15097
  15. keobrien commented on Nov 18, 2020

    @keobrien

    I'm still seeing these issues on iOS TalkBack & Android TalkBack for the DropdownButtonFormField widget.

    Issues:

    1. VoiceOver & TalkBack - DropdownButtonFormField does not gain accessibility focus when using the native keyboard next button from another field.
    2. VoiceOver & TalkBack - After making a selection from DropdownButtonFormField, accessibility focus does not return to the field, accessibility focus is sent to the top of the page.
    3. VoiceOver - When opening the DropdownButtonFormField, accessibility focus is sent to the hidden "Dismiss" link at the bottom. A user has to swipe back to get to the dropdown items, accessibility focus should be placed at the top of the list.

    Code Example:

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          home: Home(),
        );
      }
    }
    
    class Home extends StatefulWidget {
      @override
      _HomeState createState() => _HomeState();
    }
    
    class _HomeState extends State<Home> {
      FocusNode dropdownFocus = FocusNode();
      String dropdownValue;
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Home'),
          ),
          body: GestureDetector(
            child: Column(
              children: [
                TextFormField(
                  decoration: InputDecoration(labelText: 'Test Field 1'),
                  onFieldSubmitted: (_) => dropdownFocus.requestFocus(),
                  textInputAction: TextInputAction.next,
                ),
                DropdownButtonFormField(
                  focusNode: dropdownFocus,
                  decoration: InputDecoration(
                    labelText: 'Test Field 2',
                  ),
                  value: dropdownValue,
                  items: [
                    DropdownMenuItem(
                      value: 'a',
                      child: Text('A'),
                    ),
                    DropdownMenuItem(
                      value: 'b',
                      child: Text('B'),
                    )
                  ],
                  onChanged: (newValue) {
                    setState(() {
                      dropdownValue = newValue;
                    });
                  },
                ),
              ],
            ),
          ),
        );
      }
    }
    
  16. GabrieleSuzart commented on Jul 26, 2021

    @GabrieleSuzart

    Hi, I'm having the same problem! I put a DropdownButton on the screen and then tested it with VoiceOver screen reader, after selecting a new option the reader focus is directed to the top of the screen, reading everything again, which makes the experience really bad for blind people.

  17. github-actions commented on Aug 9, 2021

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  18. locked as resolved and limited conversation to collaborators on Aug 9, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

a: accessibilityAccessibility, e.g. VoiceOver or TalkBack. (aka a11y)frameworkflutter/packages/flutter repository. See also f: labels.p: material_uimaterial_ui package in flutter/packages

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions