Flutter Form Validation
Goal
Implements stateful form validation in Flutter using
Form
,
TextFormField
, and
GlobalKey
createState ( ) =
_CustomValidatedFormState ( ) ; } class _CustomValidatedFormState extends State < CustomValidatedForm
{ // Instantiate the GlobalKey once in the State object final _formKey = GlobalKey < FormState
( ) ; @override Widget build ( BuildContext context ) { return Form ( key : _formKey , child : Column ( crossAxisAlignment : CrossAxisAlignment . start , children : < Widget
[ // Form fields will be injected here ] , ) , ) ; } } Implement TextFormFields with Validation Logic Inject TextFormField widgets into the Form 's widget tree. Provide a validator function for each field. TextFormField ( decoration : const InputDecoration ( hintText : 'Enter your email' , labelText : 'Email' , ) , validator : ( String ? value ) { if ( value == null || value . isEmpty ) { return 'Please enter an email address' ; } if ( ! value . contains ( '@' ) ) { return 'Please enter a valid email address' ; } // Return null if the input is valid return null ; } , onSaved : ( String ? value ) { // Handle save logic here } , ) Implement the Submit Action and Validation Trigger Create a button that accesses the FormState via the GlobalKey to trigger validation. Padding ( padding : const EdgeInsets . symmetric ( vertical : 16.0 ) , child : ElevatedButton ( onPressed : ( ) { // Validate returns true if the form is valid, or false otherwise. if ( _formKey . currentState ! . validate ( ) ) { // Save the form fields if necessary _formKey . currentState ! . save ( ) ; // Provide success feedback ScaffoldMessenger . of ( context ) . showSnackBar ( const SnackBar ( content : Text ( 'Processing Data' ) ) , ) ; } } , child : const Text ( 'Submit' ) , ) , ) STOP AND ASK THE USER: Pause implementation and ask the user for the following context: "What specific fields do you need in this form?" "What are the exact validation rules for each field (e.g., regex patterns, minimum lengths)?" "What action should occur upon successful validation (e.g., API payload submission, navigation)?" Validate-and-Fix Loop After generating the form, verify the following: Ensure _formKey.currentState!.validate() is null-checked properly using the bang operator ( ! ) or safe calls if the key might be detached. Verify that every validator function explicitly returns null on success. Returning an empty string ( "" ) will trigger an error state with no text. Constraints DO NOT instantiate the GlobalKey
inside the build method. It must be a persistent member of the State class. DO NOT use a StatelessWidget for the form container unless the GlobalKey is being passed down from a stateful parent. DO NOT use standard TextField widgets if you require built-in form validation; you must use TextFormField (which wraps TextField in a FormField ). ALWAYS return null from a validator function when the input is valid. ALWAYS ensure the Form widget is a common ancestor to all TextFormField widgets that need to be validated together.