-
-
Notifications
You must be signed in to change notification settings - Fork 199
Description
Describe the bug
When navigating with a screen reader on Flutter Web, a discrepancy occurs between the semantic focus and the input focus for the Pinput
widget. The screen reader successfully navigates to and announces the Pinput
widget (it gains semantic focus).
However, the actual keyboard input focus does not follow. It remains on the previously focused element. As a result, the user hears that they are on the pin input field but is unable to type into it.
While standard Tab
key navigation or clicking on thePinput
works correctly, navigation via the screen reader's virtual cursor does not.
To Reproduce
Steps to reproduce the behavior:
- Run the minimal reproduction code (provided below) on the web (
flutter run -d chrome
). - Enable a screen reader (e.g., VoiceOver on macOS).
- Navigate from the "Regular TextField" using the screen reader's "next item" gesture.
- Observe: The screen reader's focus moves to the
Pinput
widget, and it is announced correctly. This is the semantic focus. - Observe: The visual input cursor (the blinking caret) remains on the "Regular TextField". This is the input focus.
- Try to type. The characters will not appear in the
Pinput
, confirming the input focus was not transferred.
Video
bug_video.mov
Pinput version: 5.0.1
Result of: flutter doctor --verbose
[✓] Flutter (Channel stable, 3.32.0, on macOS 14.1 23B2073 darwin-arm64, locale en-PL) • Flutter version 3.32.0 on channel stable at /Users/adam/fvm/versions/3.32.0 • Upstream repository https://github.com/flutter/flutter.git • Framework revision be698c48a6 (9 weeks ago), 2025-05-19 12:59:14 -0700 • Engine revision 1881800949 • Dart version 3.8.0 • DevTools version 2.45.1[!] Android toolchain - develop for Android devices (Android SDK version 35.0.0)
• Android SDK at /Users/adam/Library/Android/sdk
✗ cmdline-tools component is missing.
Try installing or updating Android Studio.
Alternatively, download the tools from
https://developer.android.com/studio#command-line-tools-only and make sure to set
the ANDROID_HOME environment variable.
See https://developer.android.com/studio/command-line for more details.
✗ Android license status unknown.
Runflutter doctor --android-licenses
to accept the SDK licenses.
See https://flutter.dev/to/macos-android-setup for more details.[✓] Xcode - develop for iOS and macOS (Xcode 15.4)
• Xcode at /Applications/Xcode.app/Contents/Developer
• Build 15F31d
• CocoaPods version 1.16.2[✓] Chrome - develop for the web
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome[✓] Android Studio (version 2024.2)
• Android Studio at /Applications/Android Studio.app/Contents
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build 21.0.5+-12932927-b750.29)[✓] Android Studio (version 2025.1)
• Android Studio at /Users/adam/Documents/06/Android Studio.app/Contents
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build 21.0.6+-13391695-b895.109)[✓] VS Code (version 1.102.1)
• VS Code at /Applications/Visual Studio Code.app/Contents
• Flutter extension version 3.114.0[✓] Connected device (4 available)
• sdk gphone64 arm64 (mobile) • emulator-5554 • android-arm64
• Android 14 (API 34) (emulator)
• Adam’s iPhone (wireless) (mobile) • 00008130-000449540208001C • ios
• iOS 18.5 22F76
• macOS (desktop) • macos • darwin-arm64
• macOS 14.1 23B2073 darwin-arm64
• Chrome (web) • chrome • web-javascript
• Google Chrome 138.0.7204.158
! Error: Browsing on the local area network for iPhone 13 von Manu. Ensure the device
is unlocked and attached with a cable or associated with the same local area network
as this Mac.
The device must be opted into Developer Mode to connect wirelessly. (code -27)[✓] Network resources
• All expected network resources are available.! Doctor found issues in 1 category.
Device:
This issue occurs on desktop web browsers.
- Device: Desktop
- OS: macOS,
- Browser: Chrome
Additional context
Here is a minimal, self-contained example to reproduce the bug.
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:pinput/pinput.dart';
void main() {
runApp(const PinputAccessibilityRepro());
if (kIsWeb) {
SemanticsBinding.instance.ensureSemantics();
}
}
class PinputAccessibilityRepro extends StatelessWidget {
const PinputAccessibilityRepro({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Pinput Accessibility Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const ReproHomePage(),
);
}
}
class ReproHomePage extends StatefulWidget {
const ReproHomePage({super.key});
@override
State<ReproHomePage> createState() => _ReproHomePageState();
}
class _ReproHomePageState extends State<ReproHomePage> {
final FocusNode _pinputFocusNode = FocusNode();
final TextEditingController _pinputController = TextEditingController();
@override
void dispose() {
_pinputFocusNode.dispose();
_pinputController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final defaultPinTheme = PinTheme(
width: 56,
height: 56,
textStyle: const TextStyle(
fontSize: 22,
color: Color.fromRGBO(30, 60, 87, 1),
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.grey),
),
);
return Scaffold(
appBar: AppBar(
title: const Text('Pinput Accessibility Issue'),
),
body: Center(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const TextField(
decoration: InputDecoration(
labelText: 'Regular TextField (works)',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 40),
Pinput(
length: 6,
controller: _pinputController,
focusNode: _pinputFocusNode,
defaultPinTheme: defaultPinTheme,
focusedPinTheme: defaultPinTheme.copyWith(
decoration: defaultPinTheme.decoration!.copyWith(
border: Border.all(color: Colors.blue),
),
),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {},
child: const Text('Another focusable element'),
),
],
),
),
),
);
}
}