In Flutter, the user can shift the focus between multiple TextFormFields inside a Form by using the soft keyboard (not by tapping the TextFormFields). This article shows you 2 ways to do so.
FocusScope.of(context).nextFocus()
This method is simple to implement.
Example Preview
This sample app contains a form with some TextFormFields. When a user focuses on a TextFormField, the soft keyboard will show up and provide a Next button that can be used to move the focus to the next field.
Here’s how it works on iOS and Android:
The complete code
// main.dart
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
// Remove the DEBUG banner
debugShowCheckedModeBanner: false,
title: 'KindaCode.com',
theme: ThemeData(
primarySwatch: Colors.amber,
),
home: const HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('KindaCode.com')),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(25),
child: Form(
child: Column(children: [
// Email text field
TextFormField(
textInputAction: TextInputAction.next,
decoration: const InputDecoration(labelText: 'Email'),
onEditingComplete: () => FocusScope.of(context).nextFocus(),
),
const SizedBox(height: 25),
// Name text field
TextFormField(
textInputAction: TextInputAction.next,
decoration: const InputDecoration(labelText: 'Name'),
onEditingComplete: () => FocusScope.of(context).nextFocus()),
const SizedBox(height: 25),
// Address text field
TextFormField(
textInputAction: TextInputAction.next,
decoration: const InputDecoration(labelText: 'Address'),
onEditingComplete: () => FocusScope.of(context).nextFocus()),
const SizedBox(height: 25),
// Job text field
TextFormField(
textInputAction: TextInputAction.done,
decoration: const InputDecoration(labelText: 'Job'),
// This is the last text field so there is no need to move the focus
onEditingComplete: () => FocusScope.of(context).unfocus())
]),
),
),
),
);
}
}
FocusScope.of(context).requestFocus()
This method is more complicated than the first one, but it’s more customizable. You can drive the focus to any TextFormField you want to, not just the next one.
Example Preview
The Code
The complete code in main.dart with explanations:
// main.dart
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const MaterialApp(
// Hide the debug banner
debugShowCheckedModeBanner: false,
title: 'Kindacode.com',
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
// Create a global key that uniquely identifies the Form widget
final _formKey = GlobalKey<FormState>();
// Focus nodes
late FocusNode _nameFocusNode;
late FocusNode _addressFocusNode;
late FocusNode _jobFocusNode;
// Create the focus nodes
@override
void initState() {
_nameFocusNode = FocusNode();
_addressFocusNode = FocusNode();
_jobFocusNode = FocusNode();
super.initState();
}
// Clean the focus nodes
@override
void dispose() {
_nameFocusNode.dispose();
_addressFocusNode.dispose();
_jobFocusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text(
'Kindacode.com',
),
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(25),
child: Form(
key: _formKey,
child: Column(children: [
// Email text field
TextFormField(
textInputAction: TextInputAction.next,
decoration: const InputDecoration(labelText: 'Email'),
onFieldSubmitted: (_) =>
FocusScope.of(context).requestFocus(_nameFocusNode),
),
const SizedBox(height: 25),
// Name text field
TextFormField(
textInputAction: TextInputAction.next,
decoration: const InputDecoration(labelText: 'Name'),
focusNode: _nameFocusNode,
onFieldSubmitted: (_) =>
FocusScope.of(context).requestFocus(_addressFocusNode)),
const SizedBox(height: 25),
// Address text field
TextFormField(
textInputAction: TextInputAction.next,
decoration: const InputDecoration(labelText: 'Address'),
focusNode: _addressFocusNode,
onFieldSubmitted: (_) =>
FocusScope.of(context).requestFocus(_jobFocusNode)),
const SizedBox(height: 25),
// Job text field
TextFormField(
textInputAction: TextInputAction.done,
focusNode: _jobFocusNode,
decoration: const InputDecoration(labelText: 'Job'),
// This is the last text field so there is no need to move the focus
)
]),
),
),
));
}
}
Conclusion
We’ve explored more than one technique to allow the user to shift the TextFormfield focus using the soft keyboard. If you’d like to learn more new and amazing things about Flutter, take a look at the following articles:
- Customize Borders of TextField/TextFormField in Flutter
- Flutter: Creating an Auto-Resize TextField
- Flutter: Make a TextField Read-Only or Disabled
- Flutter TextField: Styling labelText, hintText, and errorText
- Flutter & Hive Database: CRUD Example
- Flutter and Firestore Database: CRUD example
You can also check out our Flutter category page or Dart category page for the latest tutorials and examples.