Popular Searches
Popular Course Categories
Popular Courses

Validating email, password, and other inputs

Validating email, password, and other inputs

Flutter Forms & User Input


Validating Email, Password, and Other Inputs in Flutter


Input validation is an important part of Flutter application development. It ensures that the information entered by users follows the expected format and required rules before the application processes or submits it.


Flutter provides Form, TextFormField, FormField, and validator functions to build structured and reusable input validation. A validator returns an error message when input is invalid and returns null when the input is valid.




1. Why Input Validation Is Important



  • Prevents empty or incomplete information.

  • Checks whether an email has a valid format.

  • Ensures passwords satisfy application requirements.

  • Checks phone numbers and numeric values.

  • Prevents invalid data from being submitted accidentally.

  • Provides useful feedback to users.

  • Improves the overall quality of application data.




2. Common Inputs That Need Validation














InputCommon Validation Rules
NameRequired, minimum length, allowed characters
EmailRequired, valid email format
PasswordRequired, minimum length, uppercase/lowercase/number rules if required
Confirm PasswordRequired and must match password
Phone NumberRequired, numeric, expected number of digits
AgeRequired, numeric, minimum/maximum range
UsernameRequired, length, allowed characters
URLRequired if applicable and valid URL format
PINRequired, numeric, exact length
AddressRequired, minimum length



3. Basic Validation Structure


A common Flutter validation structure contains a Form, a GlobalKey, one or more TextFormField widgets, and a submit button.


final _formKey = GlobalKey();

Form(
  key: _formKey,
  child: Column(
    children: [
      TextFormField(
        validator: (value) {
          if (value == null || value.isEmpty) {
            return 'This field is required';
          }
          return null;
        },
      ),
      ElevatedButton(
        onPressed: () {
          if (_formKey.currentState!.validate()) {
            print('Form is valid');
          }
        },
        child: const Text('Submit'),
      ),
    ],
  ),
)


Flutter's official form-validation workflow uses a Form with a key, TextFormField validators, and FormState.validate() during submission. :contentReference[oaicite:0]{index=0}




4. Understanding the validator Function


The validator function receives the current input value and determines whether the value is acceptable.


validator: (value) {
  if (value == null || value.isEmpty) {
    return 'This field is required';
  }
  return null;
}

Validator Rules



  • Return a String containing an error message when the value is invalid.

  • Return null when the value is valid.

  • Keep error messages clear and useful.

  • Do not rely only on client-side validation for security.




5. Validating Required Fields


The first validation rule for most fields is checking whether the user has entered something.


TextFormField(
  decoration: const InputDecoration(
    labelText: 'Full Name',
  ),
  validator: (value) {
    if (value == null || value.trim().isEmpty) {
      return 'Full name is required';
    }
    return null;
  },
)

Using trim() helps prevent an input containing only spaces from being treated as valid.




6. Validating Name Input


Name validation can check whether the field is required, whether the name is long enough, and whether it contains acceptable characters.


TextFormField(
  decoration: const InputDecoration(
    labelText: 'Full Name',
  ),
  validator: (value) {
    if (value == null || value.trim().isEmpty) {
      return 'Please enter your name';
    }

    final name = value.trim();

    if (name.length < 3) {
      return 'Name must contain at least 3 characters';
    }

    if (!RegExp(r"^[a-zA-Z\s'-]+$").hasMatch(name)) {
      return 'Enter a valid name';
    }

    return null;
  },
)




7. Validating Email Addresses


Email validation is commonly required in registration, login, profile, subscription, and contact forms.


A basic email validator can check whether the input is empty and whether it follows a reasonable email pattern.


TextFormField(
  keyboardType: TextInputType.emailAddress,
  decoration: const InputDecoration(
    labelText: 'Email Address',
    hintText: '[email protected]',
  ),
  validator: (value) {
    if (value == null || value.trim().isEmpty) {
      return 'Email address is required';
    }

    final email = value.trim();

    final emailPattern =
        RegExp(r'^[^@\s]+@[^@\s]+\.[^@\s]+$');

    if (!emailPattern.hasMatch(email)) {
      return 'Enter a valid email address';
    }

    return null;
  },
)


How Email Validation Works



  1. Check whether the field is empty.

  2. Remove unnecessary leading and trailing spaces.

  3. Check the email against a suitable pattern.

  4. Return an error message if the format is invalid.

  5. Return null when the value passes validation.




8. Email Validation Examples











InputExpected Result
[email protected]Valid
[email protected]Valid
[email protected]Valid
studentexample.comInvalid
student@Invalid
@example.comInvalid
student@exampleInvalid

Email patterns should be treated as format checks rather than proof that an address exists. Applications that need to verify ownership should use an appropriate email verification process.




9. Validating Passwords


Password validation is used to make sure the password meets the application's security requirements.


A simple password policy may require a minimum number of characters.


TextFormField(
  obscureText: true,
  decoration: const InputDecoration(
    labelText: 'Password',
  ),
  validator: (value) {
    if (value == null || value.isEmpty) {
      return 'Password is required';
    }

    if (value.length < 8) {
      return 'Password must contain at least 8 characters';
    }

    return null;
  },
)




10. Password Validation with Multiple Rules


Some applications require passwords to contain uppercase letters, lowercase letters, numbers, or special characters.


String? validatePassword(String? value) {
  if (value == null || value.isEmpty) {
    return 'Password is required';
  }

  if (value.length < 8) {
    return 'Password must contain at least 8 characters';
  }

  if (!RegExp(r'[A-Z]').hasMatch(value)) {
    return 'Password must contain an uppercase letter';
  }

  if (!RegExp(r'[a-z]').hasMatch(value)) {
    return 'Password must contain a lowercase letter';
  }

  if (!RegExp(r'[0-9]').hasMatch(value)) {
    return 'Password must contain a number';
  }

  if (!RegExp(r'[!@#$%^&*(),.?":{}|<>]').hasMatch(value)) {
    return 'Password must contain a special character';
  }

  return null;
}


Use password requirements that match the application's actual security policy. Avoid adding arbitrary complexity rules unless they serve a clear purpose.




11. Confirm Password Validation


Confirm Password fields are commonly used during account registration and password changes.


final passwordController = TextEditingController();

TextFormField(
  controller: passwordController,
  obscureText: true,
  decoration: const InputDecoration(
    labelText: 'Password',
  ),
  validator: (value) {
    if (value == null || value.isEmpty) {
      return 'Password is required';
    }

    if (value.length < 8) {
      return 'Password must contain at least 8 characters';
    }

    return null;
  },
),

TextFormField(
  obscureText: true,
  decoration: const InputDecoration(
    labelText: 'Confirm Password',
  ),
  validator: (value) {
    if (value == null || value.isEmpty) {
      return 'Please confirm your password';
    }

    if (value != passwordController.text) {
      return 'Passwords do not match';
    }

    return null;
  },
)




12. Validating Username


A username can be restricted to letters, numbers, underscores, or other characters according to the application's requirements.


String? validateUsername(String? value) {
  if (value == null || value.trim().isEmpty) {
    return 'Username is required';
  }

  final username = value.trim();

  if (username.length < 4) {
    return 'Username must contain at least 4 characters';
  }

  if (username.length > 20) {
    return 'Username cannot exceed 20 characters';
  }

  if (!RegExp(r'^[a-zA-Z0-9_]+$').hasMatch(username)) {
    return 'Use only letters, numbers, and underscore';
  }

  return null;
}




13. Validating Phone Numbers


Phone number validation depends on the format supported by the application. If the application specifically expects a 10-digit number, a simple validation rule can be used.


TextFormField(
  keyboardType: TextInputType.phone,
  decoration: const InputDecoration(
    labelText: 'Phone Number',
  ),
  validator: (value) {
    if (value == null || value.trim().isEmpty) {
      return 'Phone number is required';
    }

    final phone = value.trim();

    if (!RegExp(r'^[0-9]{10}$').hasMatch(phone)) {
      return 'Enter a valid 10-digit phone number';
    }

    return null;
  },
)


For international applications, avoid assuming every phone number has the same length or format. Use a format appropriate to the application's supported countries.




14. Validating Age


Age can be checked to make sure it is numeric and falls within an acceptable range.


TextFormField(
  keyboardType: TextInputType.number,
  decoration: const InputDecoration(
    labelText: 'Age',
  ),
  validator: (value) {
    if (value == null || value.trim().isEmpty) {
      return 'Age is required';
    }

    final age = int.tryParse(value.trim());

    if (age == null) {
      return 'Enter a valid age';
    }

    if (age < 18) {
      return 'Age must be 18 or above';
    }

    if (age > 120) {
      return 'Enter a valid age';
    }

    return null;
  },
)




15. Validating Numeric Input


Numeric validation is useful for quantity, price, marks, salary, age, and other numerical fields.


TextFormField(
  keyboardType: TextInputType.number,
  decoration: const InputDecoration(
    labelText: 'Quantity',
  ),
  validator: (value) {
    if (value == null || value.trim().isEmpty) {
      return 'Quantity is required';
    }

    final quantity = int.tryParse(value.trim());

    if (quantity == null) {
      return 'Enter a valid number';
    }

    if (quantity <= 0) {
      return 'Quantity must be greater than zero';
    }

    return null;
  },
)




16. Validating Decimal Numbers


Use double.tryParse() when a field can contain decimal values.


TextFormField(
  keyboardType: const TextInputType.numberWithOptions(
    decimal: true,
  ),
  decoration: const InputDecoration(
    labelText: 'Price',
  ),
  validator: (value) {
    if (value == null || value.trim().isEmpty) {
      return 'Price is required';
    }

    final price = double.tryParse(value.trim());

    if (price == null) {
      return 'Enter a valid price';
    }

    if (price < 0) {
      return 'Price cannot be negative';
    }

    return null;
  },
)




17. Validating PIN


A PIN can be validated by checking whether it contains exactly the required number of digits.


TextFormField(
  keyboardType: TextInputType.number,
  obscureText: true,
  maxLength: 4,
  decoration: const InputDecoration(
    labelText: 'PIN',
  ),
  validator: (value) {
    if (value == null || value.isEmpty) {
      return 'PIN is required';
    }

    if (!RegExp(r'^[0-9]{4}$').hasMatch(value)) {
      return 'PIN must contain exactly 4 digits';
    }

    return null;
  },
)




18. Validating URLs


Applications that collect website addresses can validate the basic structure of a URL.


String? validateUrl(String? value) {
  if (value == null || value.trim().isEmpty) {
    return 'Website URL is required';
  }

  final uri = Uri.tryParse(value.trim());

  if (uri == null ||
      !uri.hasScheme ||
      !['http', 'https'].contains(uri.scheme) ||
      uri.host.isEmpty) {
    return 'Enter a valid website URL';
  }

  return null;
}




19. Validating Address Input


Address fields often require only a non-empty value and a reasonable minimum length.


TextFormField(
  maxLines: 3,
  decoration: const InputDecoration(
    labelText: 'Address',
    border: OutlineInputBorder(),
  ),
  validator: (value) {
    if (value == null || value.trim().isEmpty) {
      return 'Address is required';
    }

    if (value.trim().length < 10) {
      return 'Please enter a complete address';
    }

    return null;
  },
)




20. Validating a Dropdown


Dropdown values can be validated by checking whether the user selected an option.


String? selectedCountry;

DropdownButtonFormField(
  decoration: const InputDecoration(
    labelText: 'Country',
    border: OutlineInputBorder(),
  ),
  items: const [
    DropdownMenuItem(
      value: 'India',
      child: Text('India'),
    ),
    DropdownMenuItem(
      value: 'USA',
      child: Text('USA'),
    ),
    DropdownMenuItem(
      value: 'UK',
      child: Text('UK'),
    ),
  ],
  onChanged: (value) {
    setState(() {
      selectedCountry = value;
    });
  },
  validator: (value) {
    if (value == null) {
      return 'Please select a country';
    }
    return null;
  },
)




21. Validating Checkbox Input


Checkboxes are often used for terms and conditions or consent requirements.


bool acceptedTerms = false;

CheckboxListTile(
  title: const Text('I accept the Terms and Conditions'),
  value: acceptedTerms,
  onChanged: (value) {
    setState(() {
      acceptedTerms = value ?? false;
    });
  },
)


Before submitting:


if (!acceptedTerms) {
  ScaffoldMessenger.of(context).showSnackBar(
    const SnackBar(
      content: Text('Please accept the Terms and Conditions'),
    ),
  );
  return;
}



22. Reusable Email Validator


When the same validation rule is needed in multiple screens, create a reusable function.


String? validateEmail(String? value) {
  if (value == null || value.trim().isEmpty) {
    return 'Email is required';
  }

  final email = value.trim();

  final pattern =
      RegExp(r'^[^@\s]+@[^@\s]+\.[^@\s]+$');

  if (!pattern.hasMatch(email)) {
    return 'Enter a valid email address';
  }

  return null;
}


Use it directly with a TextFormField:


TextFormField(
  keyboardType: TextInputType.emailAddress,
  validator: validateEmail,
)



23. Reusable Password Validator


String? validatePassword(String? value) {
  if (value == null || value.isEmpty) {
    return 'Password is required';
  }

  if (value.length < 8) {
    return 'Password must contain at least 8 characters';
  }

  return null;
}


Use it like this:


TextFormField(
  obscureText: true,
  validator: validatePassword,
)



24. Reusable Phone Validator


String? validatePhone(String? value) {
  if (value == null || value.trim().isEmpty) {
    return 'Phone number is required';
  }

  if (!RegExp(r'^[0-9]{10}$').hasMatch(value.trim())) {
    return 'Enter a valid 10-digit phone number';
  }

  return null;
}




25. Reusable Required Field Validator


String? validateRequired(
  String? value,
  String fieldName,
) {
  if (value == null || value.trim().isEmpty) {
    return '$fieldName is required';
  }

  return null;
}


Example:


TextFormField(
  validator: (value) {
    return validateRequired(value, 'Full Name');
  },
)



26. Using AutovalidateMode


AutovalidateMode controls when validation messages are automatically displayed.


TextFormField(
  autovalidateMode: AutovalidateMode.onUserInteraction,
  validator: validateEmail,
)






ModeDescription
AutovalidateMode.disabledAutomatic validation is disabled.
AutovalidateMode.alwaysValidation occurs automatically.
AutovalidateMode.onUserInteractionValidation occurs after the user interacts with the field.



27. Reading Input with TextEditingController


TextEditingController can be used when the application needs direct access to the current text value.


final emailController = TextEditingController();

TextFormField(
  controller: emailController,
  validator: validateEmail,
)


Read the value:


final email = emailController.text.trim();
print(email);

Controllers should be disposed when they are no longer needed.


@override
void dispose() {
  emailController.dispose();
  super.dispose();
}

Flutter's documentation recommends disposing of TextEditingController objects when they are no longer needed. :contentReference[oaicite:1]{index=1}




28. Input Validation with Form Submission


All fields can be validated together by calling validate() on the form state.


void submitForm() {
  if (_formKey.currentState!.validate()) {
    print('All inputs are valid');
    // Send data to an API or save it locally.
  } else {
    print('Please correct the errors');
  }
}

Flutter runs the validators for the form fields when validate() is called and returns a boolean result. :contentReference[oaicite:2]{index=2}




29. Complete Email and Password Validation Example


import 'package:flutter/material.dart';

class LoginForm extends StatefulWidget {
  const LoginForm({super.key});

  @override
  State createState() => _LoginFormState();
}

class _LoginFormState extends State {
  final _formKey = GlobalKey();
  final emailController = TextEditingController();
  final passwordController = TextEditingController();

  String? validateEmail(String? value) {
    if (value == null || value.trim().isEmpty) {
      return 'Email is required';
    }

    final email = value.trim();
    final pattern =
        RegExp(r'^[^@\s]+@[^@\s]+\.[^@\s]+$');

    if (!pattern.hasMatch(email)) {
      return 'Enter a valid email address';
    }

    return null;
  }

  String? validatePassword(String? value) {
    if (value == null || value.isEmpty) {
      return 'Password is required';
    }

    if (value.length < 8) {
      return 'Password must contain at least 8 characters';
    }

    return null;
  }

  void login() {
    if (!_formKey.currentState!.validate()) {
      return;
    }

    final email = emailController.text.trim();
    final password = passwordController.text;

    print('Email: $email');
    print('Password length: ${password.length}');

    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(
        content: Text('Login form is valid'),
      ),
    );
  }

  @override
  void dispose() {
    emailController.dispose();
    passwordController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Login'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Form(
          key: _formKey,
          child: Column(
            children: [
              TextFormField(
                controller: emailController,
                keyboardType: TextInputType.emailAddress,
                decoration: const InputDecoration(
                  labelText: 'Email',
                  border: OutlineInputBorder(),
                ),
                validator: validateEmail,
              ),
              const SizedBox(height: 16),
              TextFormField(
                controller: passwordController,
                obscureText: true,
                decoration: const InputDecoration(
                  labelText: 'Password',
                  border: OutlineInputBorder(),
                ),
                validator: validatePassword,
              ),
              const SizedBox(height: 20),
              SizedBox(
                width: double.infinity,
                child: ElevatedButton(
                  onPressed: login,
                  child: const Text('Login'),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}




30. Complete Registration Validation Example


import 'package:flutter/material.dart';

class RegistrationForm extends StatefulWidget {
  const RegistrationForm({super.key});

  @override
  State createState() => _RegistrationFormState();
}

class _RegistrationFormState extends State {
  final _formKey = GlobalKey();

  final nameController = TextEditingController();
  final emailController = TextEditingController();
  final phoneController = TextEditingController();
  final passwordController = TextEditingController();
  final confirmPasswordController = TextEditingController();

  bool acceptedTerms = false;

  String? validateName(String? value) {
    if (value == null || value.trim().isEmpty) {
      return 'Name is required';
    }

    if (value.trim().length < 3) {
      return 'Name must contain at least 3 characters';
    }

    return null;
  }

  String? validateEmail(String? value) {
    if (value == null || value.trim().isEmpty) {
      return 'Email is required';
    }

    final pattern =
        RegExp(r'^[^@\s]+@[^@\s]+\.[^@\s]+$');

    if (!pattern.hasMatch(value.trim())) {
      return 'Enter a valid email address';
    }

    return null;
  }

  String? validatePhone(String? value) {
    if (value == null || value.trim().isEmpty) {
      return 'Phone number is required';
    }

    if (!RegExp(r'^[0-9]{10}$').hasMatch(value.trim())) {
      return 'Enter a valid 10-digit phone number';
    }

    return null;
  }

  String? validatePassword(String? value) {
    if (value == null || value.isEmpty) {
      return 'Password is required';
    }

    if (value.length < 8) {
      return 'Password must contain at least 8 characters';
    }

    if (!RegExp(r'[A-Z]').hasMatch(value)) {
      return 'Password must contain an uppercase letter';
    }

    if (!RegExp(r'[0-9]').hasMatch(value)) {
      return 'Password must contain a number';
    }

    return null;
  }

  void submitForm() {
    if (!acceptedTerms) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text('Please accept the Terms and Conditions'),
        ),
      );
      return;
    }

    if (!_formKey.currentState!.validate()) {
      return;
    }

    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(
        content: Text('Registration successful'),
      ),
    );
  }

  @override
  void dispose() {
    nameController.dispose();
    emailController.dispose();
    phoneController.dispose();
    passwordController.dispose();
    confirmPasswordController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Registration'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Form(
          key: _formKey,
          child: ListView(
            children: [
              TextFormField(
                controller: nameController,
                decoration: const InputDecoration(
                  labelText: 'Full Name',
                  border: OutlineInputBorder(),
                ),
                validator: validateName,
              ),
              const SizedBox(height: 16),
              TextFormField(
                controller: emailController,
                keyboardType: TextInputType.emailAddress,
                decoration: const InputDecoration(
                  labelText: 'Email',
                  border: OutlineInputBorder(),
                ),
                validator: validateEmail,
              ),
              const SizedBox(height: 16),
              TextFormField(
                controller: phoneController,
                keyboardType: TextInputType.phone,
                decoration: const InputDecoration(
                  labelText: 'Phone Number',
                  border: OutlineInputBorder(),
                ),
                validator: validatePhone,
              ),
              const SizedBox(height: 16),
              TextFormField(
                controller: passwordController,
                obscureText: true,
                decoration: const InputDecoration(
                  labelText: 'Password',
                  border: OutlineInputBorder(),
                ),
                validator: validatePassword,
              ),
              const SizedBox(height: 16),
              TextFormField(
                controller: confirmPasswordController,
                obscureText: true,
                decoration: const InputDecoration(
                  labelText: 'Confirm Password',
                  border: OutlineInputBorder(),
                ),
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Please confirm your password';
                  }

                  if (value != passwordController.text) {
                    return 'Passwords do not match';
                  }

                  return null;
                },
              ),
              const SizedBox(height: 8),
              CheckboxListTile(
                contentPadding: EdgeInsets.zero,
                title: const Text(
                  'I accept the Terms and Conditions',
                ),
                value: acceptedTerms,
                onChanged: (value) {
                  setState(() {
                    acceptedTerms = value ?? false;
                  });
                },
              ),
              const SizedBox(height: 16),
              SizedBox(
                width: double.infinity,
                child: ElevatedButton(
                  onPressed: submitForm,
                  child: const Text('Register'),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}




31. Input Formatting vs Validation


Input formatting and validation are related but serve different purposes.








Input FormattingValidation
Controls how input is entered.Checks whether the final input is acceptable.
Can restrict characters.Can display error messages.
Can limit input length.Can enforce business rules.
Works while the user is entering data.Usually runs when validation is triggered.

Example


TextFormField(
  maxLength: 10,
  keyboardType: TextInputType.phone,
  validator: validatePhone,
)



32. Showing Validation While the User Types


For a better user experience, validation can be enabled after the user interacts with a field.


TextFormField(
  autovalidateMode: AutovalidateMode.onUserInteraction,
  validator: validateEmail,
)

This can provide immediate feedback without displaying errors before the user has interacted with the field.




33. Moving Focus to Invalid Fields


Focus management can make long forms easier to use. Flutter supports FocusNode and FocusScope for controlling which field receives focus. :contentReference[oaicite:3]{index=3}


final emailFocusNode = FocusNode();

TextFormField(
  focusNode: emailFocusNode,
  keyboardType: TextInputType.emailAddress,
  validator: validateEmail,
)


Focus nodes should be managed as long-lived objects and disposed when they are no longer needed.


@override
void dispose() {
  emailFocusNode.dispose();
  super.dispose();
}



34. Common Validation Mistakes



  • Not checking for null before processing a field value.

  • Accepting whitespace-only input.

  • Using unclear error messages.

  • Creating a new GlobalKey inside build().

  • Forgetting to call validate() before submission.

  • Forgetting to check the boolean result of validate().

  • Not disposing TextEditingController objects.

  • Not disposing FocusNode objects.

  • Comparing passwords incorrectly.

  • Using an overly restrictive email pattern.

  • Assuming every country's phone number follows the same format.

  • Relying entirely on client-side validation for security.

  • Logging sensitive values such as passwords.




35. Best Practices for Email Validation



  • Use TextInputType.emailAddress.

  • Trim unnecessary whitespace.

  • Check that the field is not empty.

  • Use a reasonable email-format check.

  • Do not assume that format validation proves the email address exists.

  • Use email verification when the application needs to confirm ownership.

  • Perform server-side validation as well.




36. Best Practices for Password Validation



  • Define password requirements clearly.

  • Use obscureText when displaying password input.

  • Do not print or log passwords.

  • Do not store plaintext passwords in application databases.

  • Use secure authentication and backend practices.

  • Keep client-side password validation consistent with the actual server policy.

  • Validate confirmation passwords against the current password value.




37. Client-Side vs Server-Side Validation


Client-Side Validation



  • Runs inside the Flutter application.

  • Provides immediate feedback.

  • Improves user experience.

  • Prevents obvious invalid submissions.


Server-Side Validation



  • Runs on the backend.

  • Protects against manipulated requests.

  • Enforces business rules.

  • Should always be used for security-sensitive operations.


Client-side validation should never be considered a replacement for server-side validation.




38. Practical Validation Rules Example













FieldValidation Rules
Full NameRequired, minimum 3 characters
EmailRequired, valid email format
PhoneRequired, expected number of digits
UsernameRequired, 4-20 characters, allowed characters only
PasswordRequired, minimum 8 characters, application-specific requirements
Confirm PasswordMust match password
AgeRequired, numeric, valid range
CountrySelection required
TermsMust be accepted



39. Practical Exercise


Create a Flutter registration form with the following fields:



  1. Full Name

  2. Username

  3. Email

  4. Phone Number

  5. Password

  6. Confirm Password

  7. Age

  8. Website

  9. Country

  10. Terms and Conditions


Implement validation for every field and display a meaningful error message whenever the entered value is invalid.


Expected Validation



  • Full Name cannot be empty.

  • Username must contain only allowed characters.

  • Email must follow a valid format.

  • Phone number must follow the application's supported format.

  • Password must satisfy the defined password policy.

  • Confirm Password must match Password.

  • Age must be numeric and within the required range.

  • Website must contain a valid HTTP or HTTPS URL when provided.

  • Country must be selected.

  • Terms and Conditions must be accepted.




40. Interview Questions


Q1. How do you validate an email in Flutter?


Use a TextFormField with a validator function that checks whether the value is present and follows an appropriate email format.


Q2. How do you validate a password?


Check the password against the application's requirements, such as minimum length and any required character classes.


Q3. How do you compare password and confirm password fields?


Use a TextEditingController for the password and compare the confirmation field's value with passwordController.text.


Q4. What does a validator return when the input is valid?


It returns null.


Q5. What does validate() do?


FormState.validate() runs the validators associated with the form fields and returns whether the form passes validation. :contentReference[oaicite:4]{index=4}


Q6. Why use TextFormField instead of TextField for form validation?


TextFormField integrates with Form and provides form-field validation functionality. :contentReference[oaicite:5]{index=5}


Q7. Why should TextEditingController be disposed?


Controllers should be disposed when they are no longer needed so their associated resources are cleaned up. :contentReference[oaicite:6]{index=6}




41. Quick Revision



  • Use Form to group related input fields.

  • Use TextFormField for form-aware text input.

  • Use validator to define validation rules.

  • Return an error message for invalid input.

  • Return null for valid input.

  • Use GlobalKey to access form state when appropriate.

  • Call validate() before submitting form data.

  • Use TextEditingController when direct access to field values is needed.

  • Dispose controllers and focus nodes when they are no longer needed.

  • Use appropriate validation rules for email, password, phone, numeric, URL, and other inputs.

  • Use clear and helpful error messages.

  • Always perform appropriate server-side validation for data sent to a backend.




42. Official Flutter Resources





43. JustAcademy Flutter Training Resources





Key Takeaways


Validating email, password, and other inputs is essential for creating reliable Flutter forms. Use TextFormField validators for individual fields, FormState.validate() for complete-form validation, and reusable validation functions when the same rules are needed in multiple places. Always combine user-friendly client-side validation with appropriate server-side validation for data sent to a backend.


whatsapp