Skip to content

Improper keyboard behavior of radio buttons #113562

@bourdakos1

Description

@bourdakos1

Steps to Reproduce

  1. Execute flutter run on the code sample
  2. Navigate to the Group1 radio buttons by pressing tab
  3. Navigate between the radio buttons using the up/down left/right arrow keys

Expected results:
Pressing an arrow key should move focus and check the next radio button in the group. If the radio button is the last in the group and the right/down arrow key is pressed it should wrap back to the first radio button in the group. Likewise, if the radio button is the first in the group and the up/left arrow key is pressed it should wrap to the last radio button in the group.

Additionally, pressing tab should move focus to the next radio group, not the next radio button.

See: https://www.w3.org/WAI/ARIA/apg/example-index/radio/radio-rating.html#kbd_label

Actual results:

Pressing arrow keys moves the focus to the next radio button, but does not mark it as checked.

Additionally, if the focus is in Group1, pressing the right arrow key moves focus to the second radio button of Group2. The focus should instead move down to the next radio button in Group1. The reverse occurs when focus is in Group2 and the up arrow is pressed.

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

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

enum Choice { a, b, c, d }

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  Choice? _choice1 = Choice.a;
  Choice? _choice2 = Choice.a;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Code Sample',
      home: Scaffold(
        body: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text('Group1'),
            Column(
              children: [
                Radio<Choice>(
                  value: Choice.a,
                  groupValue: _choice1,
                  onChanged: (Choice? value) {
                    setState(() {
                      _choice1 = value;
                    });
                  },
                ),
                Radio<Choice>(
                  value: Choice.b,
                  groupValue: _choice1,
                  onChanged: (Choice? value) {
                    setState(() {
                      _choice1 = value;
                    });
                  },
                ),
                Radio<Choice>(
                  value: Choice.c,
                  groupValue: _choice1,
                  onChanged: (Choice? value) {
                    setState(() {
                      _choice1 = value;
                    });
                  },
                ),
                Radio<Choice>(
                  value: Choice.d,
                  groupValue: _choice1,
                  onChanged: (Choice? value) {
                    setState(() {
                      _choice1 = value;
                    });
                  },
                ),
              ],
            ),
            const Text('Group2'),
            Row(
              children: [
                Radio<Choice>(
                  value: Choice.a,
                  groupValue: _choice2,
                  onChanged: (Choice? value) {
                    setState(() {
                      _choice2 = value;
                    });
                  },
                ),
                Radio<Choice>(
                  value: Choice.b,
                  groupValue: _choice2,
                  onChanged: (Choice? value) {
                    setState(() {
                      _choice2 = value;
                    });
                  },
                ),
                Radio<Choice>(
                  value: Choice.c,
                  groupValue: _choice2,
                  onChanged: (Choice? value) {
                    setState(() {
                      _choice2 = value;
                    });
                  },
                ),
                Radio<Choice>(
                  value: Choice.d,
                  groupValue: _choice2,
                  onChanged: (Choice? value) {
                    setState(() {
                      _choice2 = value;
                    });
                  },
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}
Logs
Analyzing bug_repro...                                                  
No issues found! (ran in 35.0s)
[√] Flutter (Channel master, 3.4.0-40.0.pre.7, on Microsoft Windows [Version 10.0.19042.2130], locale en-US)
    • Flutter version 3.4.0-40.0.pre.7 on channel master at C:\Users\bourdakos\Documents\flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 128b94e247 (13 days ago), 2022-10-04 15:06:53 -0400
    • Engine revision 256b8d066f
    • Dart version 2.19.0 (build 2.19.0-272.0.dev)
    • DevTools version 2.18.0

[√] Windows Version (Installed version of Windows is version 10 or higher)

[X] Android toolchain - develop for Android devices
    • Android SDK at C:\Users\bourdakos\platform-tools_r31.0.3-windows
    X cmdline-tools component is missing
      Run `path/to/sdkmanager --install "cmdline-tools;latest"`
      See https://developer.android.com/studio/command-line for more details.

[√] Chrome - develop for the web
    • Chrome at C:\Program Files\Google\Chrome\Application\chrome.exe

[√] Visual Studio - develop for Windows (Visual Studio Professional 2019 16.11.9)
    • Visual Studio at C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional
    • Visual Studio Professional 2019 version 16.11.32106.194
    • Windows 10 SDK version 10.0.19041.0

[!] Android Studio (not installed)
    • Android Studio not found; download from https://developer.android.com/studio/index.html
      (or visit https://flutter.dev/docs/get-started/install/windows#android-setup for detailed instructions).

[√] VS Code (version 1.71.2)
    • VS Code at C:\Users\bourdakos\AppData\Local\Programs\Microsoft VS Code
    • Flutter extension version 3.50.0

[√] Connected device (3 available)
    • Windows (desktop) • windows • windows-x64    • Microsoft Windows [Version 10.0.19042.2130]
    • Chrome (web)      • chrome  • web-javascript • Google Chrome 106.0.5249.119
    • Edge (web)        • edge    • web-javascript • Microsoft Edge 102.0.1245.41

[√] HTTP Host Availability
    • All required HTTP hosts are available

! Doctor found issues in 2 categories.

Metadata

Metadata

Assignees

Labels

P2Important issues not at the top of the work lista: desktopRunning on desktopf: focusFocus traversal, gaining or losing focusf: material designflutter/packages/flutter/material repository.found in release: 3.3Found to occur in 3.3found in release: 3.5Found to occur in 3.5frameworkflutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onteam-designOwned by Design Languages teamtriaged-designTriaged by Design Languages team

Type

No type

Projects

Status

Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions