skills/flutter/skills/flutter-building-forms

flutter-building-forms

SKILL.md

Building Validated Forms

Contents

Form Architecture

Implement forms using a Form widget to group and validate multiple input fields together.

  • Use a StatefulWidget: Always host your Form inside a StatefulWidget.
  • Persist the GlobalKey: Instantiate a GlobalKey<FormState> exactly once as a final variable within the State class. Do not generate a new GlobalKey inside the build method; doing so is resource-expensive and destroys the form's state on every rebuild.
  • Bind the Key: Pass the GlobalKey<FormState> to the key property of the Form widget. This uniquely identifies the form and provides access to the FormState for validation and submission.
  • Alternative Access: If dealing with highly complex widget trees where passing the key is impractical, use Form.of(context) to access the FormState from a descendant widget.

Field Validation

Use TextFormField to render Material Design text inputs with built-in validation support. TextFormField is a convenience widget that automatically wraps a standard TextField inside a FormField.

  • Implement the Validator: Provide a validator() callback function to each TextFormField.
  • Return Error Messages: If the user's input is invalid, return a String containing the specific error message. The Form will automatically rebuild to display this text below the field.
  • Return Null for Success: If the input passes validation, you must return null.

Workflow: Implementing a Validated Form

Follow this sequential workflow to implement and validate a form. Copy the checklist to track your progress.

Task Progress:

  • 1. Create a StatefulWidget and its corresponding State class.
  • 2. Instantiate final _formKey = GlobalKey<FormState>(); in the State class.
  • 3. Return a Form widget in the build method and assign key: _formKey.
  • 4. Add TextFormField widgets as descendants of the Form.
  • 5. Write a validator function for each TextFormField (return String on error, null on success).
  • 6. Add a submit button (e.g., ElevatedButton).
  • 7. Implement the validation check in the button's onPressed callback using _formKey.currentState!.validate().

Validation Decision Logic

When the user triggers the submit action, execute the following conditional logic:

  1. Call _formKey.currentState!.validate().
  2. If true (Valid): All validators returned null. Proceed with form submission (e.g., save data, make API call) and display a success indicator (e.g., a SnackBar).
  3. If false (Invalid): One or more validators returned an error string. The FormState automatically rebuilds the UI to display the error messages.
  4. Feedback Loop: Run validator -> review errors -> fix. The user must adjust their input and resubmit until validate() returns true.

Examples

Complete Validated Form Implementation

Use the following pattern to implement a robust, validated form.

import 'package:flutter/material.dart';

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

  
  State<UserRegistrationForm> createState() => _UserRegistrationFormState();
}

class _UserRegistrationFormState extends State<UserRegistrationForm> {
  // 1. Persist the GlobalKey in the State class
  final _formKey = GlobalKey<FormState>();

  
  Widget build(BuildContext context) {
    // 2. Bind the key to the Form
    return Form(
      key: _formKey,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          // 3. Add TextFormFields with validators
          TextFormField(
            decoration: const InputDecoration(
              labelText: 'Username',
              hintText: 'Enter your username',
            ),
            validator: (value) {
              if (value == null || value.isEmpty) {
                return 'Please enter a username'; // Error state
              }
              if (value.length < 4) {
                return 'Username must be at least 4 characters'; // Error state
              }
              return null; // Valid state
            },
          ),
          const SizedBox(height: 16),
          // 4. Add the submit button
          ElevatedButton(
            onPressed: () {
              // 5. Trigger validation logic
              if (_formKey.currentState!.validate()) {
                // Form is valid: Process data
                ScaffoldMessenger.of(context).showSnackBar(
                  const SnackBar(content: Text('Processing Data')),
                );
              } else {
                // Form is invalid: Errors are automatically displayed
                debugPrint('Form validation failed.');
              }
            },
            child: const Text('Submit'),
          ),
        ],
      ),
    );
  }
}
Weekly Installs
720
Repository
flutter/skills
GitHub Stars
685
First Seen
3 days ago
Installed on
codex706
gemini-cli705
opencode705
amp702
cline702
github-copilot702