0
0
Fluttermobile~5 mins

Custom validators in Flutter

Choose your learning style9 modes available
Introduction

Custom validators help check if user input is correct in ways built-in checks can't. They make sure your app gets good data.

When you want to check if a password has special rules like a number or symbol.
When you need to verify a username is not already taken or follows a pattern.
When you want to confirm an email address is in a specific format.
When you want to check a phone number matches your country's style.
When you want to give users clear messages about what is wrong with their input.
Syntax
Flutter
String? customValidator(String? value) {
  if (value == null || value.isEmpty) {
    return 'This field cannot be empty';
  }
  if (!value.contains('@')) {
    return 'Must contain @ symbol';
  }
  return null; // null means input is valid
}

The validator function returns a String?. If it returns null, the input is valid.

If it returns a String, that string is shown as an error message.

Examples
Checks if password is at least 6 characters long.
Flutter
String? passwordValidator(String? value) {
  if (value == null || value.length < 6) {
    return 'Password must be at least 6 characters';
  }
  return null;
}
Ensures username is not empty and has no spaces.
Flutter
String? usernameValidator(String? value) {
  if (value == null || value.isEmpty) {
    return 'Username cannot be empty';
  }
  if (value.contains(' ')) {
    return 'Username cannot contain spaces';
  }
  return null;
}
Sample App

This app shows a form with an email field. The custom validator checks if the email is empty or missing '@'. If invalid, it shows an error below the field. If valid, it shows a success message.

Flutter
import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Custom Validator Example')),
        body: const Padding(
          padding: EdgeInsets.all(16),
          child: MyForm(),
        ),
      ),
    );
  }
}

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

  @override
  State<MyForm> createState() => _MyFormState();
}

class _MyFormState extends State<MyForm> {
  final _formKey = GlobalKey<FormState>();
  final _emailController = TextEditingController();

  String? emailValidator(String? value) {
    if (value == null || value.isEmpty) {
      return 'Email cannot be empty';
    }
    if (!value.contains('@')) {
      return 'Email must contain @';
    }
    return null;
  }

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Column(
        children: [
          TextFormField(
            controller: _emailController,
            decoration: const InputDecoration(labelText: 'Email'),
            validator: emailValidator,
          ),
          const SizedBox(height: 20),
          ElevatedButton(
            onPressed: () {
              if (_formKey.currentState!.validate()) {
                ScaffoldMessenger.of(context).showSnackBar(
                  const SnackBar(content: Text('Email is valid!')),
                );
              }
            },
            child: const Text('Submit'),
          ),
        ],
      ),
    );
  }
}
OutputSuccess
Important Notes

Always return null from your validator when the input is valid.

Use TextFormField with a Form widget to use validators easily.

Call _formKey.currentState!.validate() to run all validators and check if form is valid.

Summary

Custom validators check user input with your own rules.

Return a string error message if input is wrong, or null if input is good.

Use validators inside TextFormField and call validate() to check.