Building Smart Forms with Flutter's Form Widget
Building Smart Forms with Flutter’s Form Widget
What You’ll Learn
Learn how to build robust, validated forms using Flutter’s built-in Form widget and validators. You’ll discover how to validate user input, display error messages, and handle form submission elegantly.
Understanding Forms in Flutter
Forms are essential for collecting user data in any app. Flutter’s Form widget provides a container for grouping and validating multiple form fields together. Combined with TextFormField and a GlobalKey<FormState>, you can create professional forms with minimal code.
The key components:
- Form: Container that groups form fields
- GlobalKey
: Provides access to form state and validation methods - TextFormField: Input field with built-in validation support
- validator: Function that returns error text or null if valid
Example: Login Form with Validation
class LoginForm extends StatefulWidget {
@override
_LoginFormState createState() => _LoginFormState();
}
class _LoginFormState extends State<LoginForm> {
final _formKey = GlobalKey<FormState>();
final _emailController = TextEditingController();
final _passwordController = TextEditingController();
@override
void dispose() {
_emailController.dispose();
_passwordController.dispose();
super.dispose();
}
String? _validateEmail(String? value) {
if (value == null || value.isEmpty) {
return 'Email is required';
}
final emailRegex = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$');
if (!emailRegex.hasMatch(value)) {
return 'Enter a valid email';
}
return null;
}
String? _validatePassword(String? value) {
if (value == null || value.isEmpty) {
return 'Password is required';
}
if (value.length < 6) {
return 'Password must be at least 6 characters';
}
return null;
}
void _submitForm() {
if (_formKey.currentState!.validate()) {
// All fields are valid, proceed with login
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Login successful!')),
);
}
}
@override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(
children: [
TextFormField(
controller: _emailController,
decoration: InputDecoration(labelText: 'Email'),
validator: _validateEmail,
keyboardType: TextInputType.emailAddress,
),
SizedBox(height: 16),
TextFormField(
controller: _passwordController,
decoration: InputDecoration(labelText: 'Password'),
validator: _validatePassword,
obscureText: true,
),
SizedBox(height: 24),
ElevatedButton(
onPressed: _submitForm,
child: Text('Login'),
),
],
),
);
}
}
How it works:
- Create a
GlobalKey<FormState>to manage form state - Wrap form fields in a
Formwidget with the key - Each
TextFormFieldhas avalidatorfunction - Call
_formKey.currentState!.validate()to trigger all validators - Validators return
nullif valid, or an error string to display
Try It Yourself
Enhance the login form by adding:
- A “Confirm Password” field that validates both passwords match
- An autovalidate mode that checks fields as the user types (use
autovalidateMode: AutovalidateMode.onUserInteraction) - A “Remember Me” checkbox using a separate form field
Tip of the Day
Use TextEditingController for fields where you need to access or manipulate the text programmatically. For simple forms where you only need the value on submit, you can skip controllers and use onSaved callbacks with _formKey.currentState!.save() instead!