Flutter Forms & Validation Explained: Complete Beginner to Advanced Guide
Learn Flutter forms and validation in depth. Understand TextFormField, Form widget, GlobalKey, validators, custom validation, real-world examples, and best practices.
Introduction
Almost every real-world application requires user input. Login forms, registration screens, profile updates, payment details — forms are everywhere.
In Flutter, building forms is simple, but proper validation is what makes your application professional and secure.
In this complete guide, we will deeply understand:
- What is a Form in Flutter?
- How TextFormField works
- Using GlobalKey for form validation
- Built-in validators
- Custom validation logic
- Real-world login form example
- Best practices
What Is a Form in Flutter?
The Form widget is a container used to group multiple form fields. It allows validation and saving of input fields together.
A Form is usually controlled using a GlobalKey.
Basic Form Structure
final _formKey = GlobalKey(); Form( key: _formKey, child: Column( children: [ TextFormField(), ElevatedButton( onPressed: () { if (_formKey.currentState!.validate()) { print("Form is valid"); } }, child: Text("Submit"), ) ], ), )
The GlobalKey allows us to access the form’s state.
Understanding TextFormField
TextFormField is used to take user input. It provides built-in support for validation.
TextFormField(
decoration: InputDecoration(
labelText: "Email",
),
validator: (value) {
if (value == null || value.isEmpty) {
return "Email cannot be empty";
}
return null;
},
)
If the validator returns a string, it shows as an error message. If it returns null, the input is valid.
Real Login Form Example
class LoginScreen extends StatefulWidget {
@override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State {
final _formKey = GlobalKey();
String email = "";
String password = "";
@override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: EdgeInsets.all(16),
child: Form(
key: _formKey,
child: Column(
children: [
TextFormField(
decoration: InputDecoration(labelText: "Email"),
onSaved: (value) => email = value ?? "",
validator: (value) {
if (value == null || value.isEmpty) {
return "Enter your email";
}
if (!value.contains("@")) {
return "Enter valid email";
}
return null;
},
),
TextFormField(
decoration: InputDecoration(labelText: "Password"),
obscureText: true,
onSaved: (value) => password = value ?? "",
validator: (value) {
if (value == null || value.length < 6) {
return "Password must be 6+ characters";
}
return null;
},
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
print("Email: $email");
print("Password: $password");
}
},
child: Text("Login"),
),
],
),
),
),
);
}
}
onSaved vs validator
- validator checks if input is valid
- onSaved stores the value after validation succeeds
Using TextEditingController
Controllers allow direct access to input values.
final emailController = TextEditingController(); TextFormField( controller: emailController, )
Remember to dispose controllers in dispose().
Custom Validation Functions
String? validatePhone(String? value) {
if (value == null || value.length != 10) {
return "Enter valid phone number";
}
return null;
}
Autovalidate Mode
Form( autovalidateMode: AutovalidateMode.onUserInteraction, )
This validates fields automatically when the user interacts.
Common Beginner Mistakes
- Forgetting GlobalKey
- Not calling validate()
- Mixing validation logic inside build()
- Not disposing controllers
Best Practices
- Keep validation logic separate
- Use meaningful error messages
- Do not overload build method
- Secure sensitive input properly
Conclusion
Forms and validation are essential in real-world Flutter applications. Understanding how Form, TextFormField, and validation work together helps you build secure and professional apps.
Once you master forms, you are ready to integrate APIs and connect your forms to backend services.
Share
What's Your Reaction?
Like
0
Dislike
0
Love
0
Funny
0
Angry
0
Sad
0
Wow
0