Description
Steps to reproduce
I encountered a problem where I have 5 TextFormFields, and some of them are conditionally hidden based on user input or state. When a field is hidden, the focus navigation (using FocusNode or keyboard traversal) stops working or breaks unexpectedly — especially when trying to move focus to the next visible field.
Expected results
When a TextFormField is conditionally hidden (e.g., based on a boolean condition), the focus should automatically skip over the hidden field and move to the next visible, focusable widget. Focus traversal should remain seamless and not break, even when fields appear or disappear dynamically.
Actual results
When a TextFormField is conditionally hidden, the focus system attempts to move to that hidden field and breaks. As a result, focus is lost or stuck, and the user cannot continue navigating to the next visible field using keyboard traversal or programmatic focus shifting (FocusScope.of(context).requestFocus(...)). This disrupts expected form navigation behavior.
Code sample
Code sample
import 'package:flutter/material.dart';
void main() {
runApp(const MaterialApp(home: FocusIssueDemo()));
}
class FocusIssueDemo extends StatefulWidget {
const FocusIssueDemo({super.key});
@override
State<FocusIssueDemo> createState() => _FocusIssueDemoState();
}
class _FocusIssueDemoState extends State<FocusIssueDemo> {
final FocusNode node1 = FocusNode();
final FocusNode node2 = FocusNode();
final FocusNode node3 = FocusNode();
final TextEditingController controller1 = TextEditingController();
final TextEditingController controller2 = TextEditingController();
final TextEditingController controller3 = TextEditingController();
bool showSecondField = true;
@override
void dispose() {
node1.dispose();
node2.dispose();
node3.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Focus Issue Sample')),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
TextFormField(
focusNode: node1,
controller: controller1,
decoration: const InputDecoration(labelText: 'Field 1'),
onFieldSubmitted: (_) {
FocusScope.of(context).requestFocus(
showSecondField ? node2 : node3);
},
),
if (showSecondField)
TextFormField(
focusNode: node2,
controller: controller2,
decoration: const InputDecoration(labelText: 'Field 2 (optional)'),
onFieldSubmitted: (_) {
FocusScope.of(context).requestFocus(node3);
},
),
TextFormField(
focusNode: node3,
controller: controller3,
decoration: const InputDecoration(labelText: 'Field 3'),
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () {
setState(() {
showSecondField = !showSecondField;
});
},
child: Text(showSecondField ? 'Hide Field 2' : 'Show Field 2'),
)
],
),
),
);
}
}
Screenshots or Video
Screenshots / Video demonstration
[Upload media here]
Logs
Logs
[Paste your logs here]
Flutter Doctor output
Doctor output
[Paste your output here]