Hello everyone and welcome to another brand new tutorial series on Flutter. Today we’re going to learn how to validate a form using Flutter.

Form plays a vital role in any mobile application today. Almost all the app in the world has a form to fill.
Overview of this tutorial. This app will have 5 text fields consisting of :
- Full name
- Email address
- Phone number
- Password
- Confirm Password
and a submit button for validation. If the user inputs are invalid according to the rules we set, we would simply display a snack bar that contains the error message e.g Invalid email address as shown below.

Let dive into coding now!!!
Creating our UI(user interface).
Create a new flutter project and clear out all generated code in the main.dart file. First, import the material package
import 'package:flutter/material.dart';
Then define the main function like this with a Stateless widget called MyApp:
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Beginner Tutorial',
theme: ThemeData(
primarySwatch: Colors.green,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(),
);
}
}
Creating a StatefulWidget for MyHomePage(), it should look like this:
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Container();
}
}
So, under _MyHomePageState extends State we’re going to declare a controller for each of our form fields:
TextEditingController _name = TextEditingController();
TextEditingController _email = TextEditingController();
TextEditingController _phn = TextEditingController();
TextEditingController _pass = TextEditingController();
TextEditingController _cpass = TextEditingController();
// we declare a _ScaffoldState here called _formKey because we're going to change the state of the app by showing the snack bar
var _formKey = GlobalKey<ScaffoldState>();
bool hidePass = true; // this is probably for showing and hiding our password
In the build widget instead of returning a Container widget, we’re going to return a Scaffold() widget, full code:
Scaffold(
key: _formKey,
appBar: AppBar(
title: Text('Simple Form Validation'),
centerTitle: true,
elevation: 0,
),
body: Center(
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: Text(
'Register Page',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.w300,
),
),
),
Padding(
padding: EdgeInsets.all(20),
child: Column(
children: <Widget>[
TextFormField(
controller: _name, // the controller we declared at the top
decoration: InputDecoration(
icon: Icon(Icons.person),
labelText: 'Full Name',
),
),
SizedBox(height: 10),
TextFormField(
controller: _email, // the controller we declared at the top
decoration: InputDecoration(
labelText: 'Email Address',
icon: Icon(Icons.mail),
),
),
SizedBox(height: 10),
TextFormField(
controller: _phn, // the controller we declared at the top
keyboardType: TextInputType.number,
decoration: InputDecoration(
labelText: 'Phone Number',
icon: Icon(Icons.call),
),
),
SizedBox(height: 10),
TextFormField(
controller: _pass,
obscureText: hidePass, // the bool we declared earlier
decoration: InputDecoration(
labelText: 'Password',
icon: Icon(Icons.security),
suffixIcon: IconButton(
icon: Icon(Icons.visibility),
onPressed: () {
showandhide(); // we are going to declare a function for showing the password inout call showandhide()
},
),
),
),
SizedBox(height: 10),
TextFormField(
obscureText: hidePass,
controller: _cpass,
decoration: InputDecoration(
labelText: 'Confirm Password',
icon: Icon(Icons.border_color),
suffixIcon: IconButton(
icon: Icon(Icons.visibility),
onPressed: () {
showandhide();
},
),
),
),
SizedBox(height: 15),
SizedBox(
width: 300,
child: MaterialButton(
onPressed: () {
formValidate(
name: _name.text,
email: _email.text,
cpass: _cpass.text,
pass: _pass.text,
phn: _phn.text,
); // formValidate consist of all of our inputs, so we're just going to declare a function to check they all if the user input is valid or otherwise.
},
child: Text(
'Submit Form',
style: TextStyle(color: Colors.white),
),
color: Colors.green,
),
),
],
),
),
],
),
),
),
);
So, we have to collect all our user input and set it inside initState and dispose of it as well.
@override
void initState() {
_name = TextEditingController();
_email = TextEditingController();
_phn = TextEditingController();
_pass = TextEditingController();
_cpass = TextEditingController();
super.initState();
}
@override
void dispose() {
_name.dispose();
_email.dispose();
_phn.dispose();
_pass.dispose();
_cpass.dispose();
super.dispose();
}
Show and hide user password:
showandhide() {
setState(() {
hidePass = !hidePass;
//this just means if the eye icon is pressed hidepass is not equal to hidepass so true != true i.e false
});
}
So after all this, we have now got to the form validation itself:
// here we collect every information we need concerning the input
formValidate({String name, email, phn, pass, cpass}) {
if (name.toString().isEmpty) {
_showInSnackBar(message: 'Full name required');
} else if (!email.toString().contains('@')) {
_showInSnackBar(message: 'Invalid email address');
} else if (phn.toString().isEmpty || phn.length != 11) {
_showInSnackBar(message: 'Invalid phone number');
} else if (pass.toString().isEmpty || pass.length != 8) {
_showInSnackBar(message: '8 character required for password');
} else if (cpass.toString() != pass.toString()) {
_showInSnackBar(message: 'Password does not match');
} else {
openDia(name: name);
//so after all the input is valid we want to display a little dialog.
}
}
Our snack bar code:
void _showInSnackBar({String message}) {
_formKey.currentState.showSnackBar(
SnackBar(
content: GestureDetector(
onTap: () {},
child: Text(
message,
style: TextStyle(color: Colors.white, fontWeight: FontWeight.w600),
),
),
duration: (Duration(seconds: 4)),
elevation: 0,
backgroundColor: Colors.black,
),
);
}
and the Dialog code as well:
openDia({String name}) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
content: Text('$name is now a verified account'),
title: Text('Registration Successful'),
actions: <Widget>[
MaterialButton(
onPressed: () {
Navigator.pop(context);
},
child: Text(
'Verified',
style: TextStyle(color: Colors.blue),
),
)
],
);
});
}
If we run our app now we should have something similar to this

Complete source code do well by staring ⭐ the repo:
Congrats, you have finally learned how to validate user input and also learned how to improve user experience by showing a beautiful error message.
If you enjoyed this article as much as I did you can support me by 👏 for this story and leave a comment below if you have any questions. Thanks
🔗 Social Media / Let's Connect 🔗 ==> Github | Twitter | Youtube | WhatsApp | LinkedIn | Patreon | Facebook.
Join the Flutter Dev Community 👨💻👨💻 ==> Facebook | Telegram | WhatsApp | Signal.
Subscribe to my Telegram channel | Youtube channel | and also to hashnode newsletter in the input box above 👆👆. Thanks
Happy Fluttering 🥰👨💻