PluginBench
Skill
Official
Pass
Audit score 90

flutter-building-forms

flutter/skills

Build validated Flutter forms with proper Form/GlobalKey/TextFormField architecture.

What is flutter-building-forms?

This skill provides a structured workflow and code pattern for building validated Flutter forms using Form, GlobalKey<FormState>, and TextFormField. Use it when creating login screens, registration forms, or any multi-field user input that requires validation before submission.

  • Defines the architecture for grouping input fields using a Form widget inside a StatefulWidget
  • Guides correct, performant use of GlobalKey<FormState> to manage form state
  • Specifies how to write validator callbacks on TextFormField that return error strings or null
  • Provides a step-by-step checklist workflow for implementing a validated form
  • Includes decision logic for handling validate() success and failure cases
  • Supplies a complete runnable Dart example of a validated registration form

How to install flutter-building-forms

npx skills add https://github.com/flutter/skills --skill flutter-building-forms
Prerequisites
  • A Flutter project using the Material widget library
Claude Code
Cursor
Windsurf
Cline

How to use flutter-building-forms

  1. 1.Create a StatefulWidget and its corresponding State class to host the form
  2. 2.Instantiate `final _formKey = GlobalKey<FormState>();` once in the State class
  3. 3.Return a Form widget in build() and assign key: _formKey
  4. 4.Add TextFormField widgets as descendants of the Form
  5. 5.Write a validator function for each TextFormField, returning an error String or null
  6. 6.Add a submit button (e.g., ElevatedButton)
  7. 7.In the button's onPressed, call _formKey.currentState!.validate() and handle the true/false result (submit data or let errors display)

Use cases

Good for
  • Building a login screen with username/password validation
  • Creating a multi-field user registration form
  • Implementing a data entry form that requires input validation before API submission
  • Adding inline error messages to text fields in a checkout or settings form
Who it's for
  • Flutter developers building user input screens
  • Coding agents generating Flutter form UI code
  • Developers implementing login or registration flows in Flutter apps

flutter-building-forms FAQ

Where should the GlobalKey<FormState> be created?

Instantiate it once as a final variable in the State class, not inside the build method, since recreating it on every rebuild is resource-expensive and destroys form state.

What should a validator function return?

Return a String error message if input is invalid, or null if the input is valid.

How do I check if a form is valid before submitting?

Call _formKey.currentState!.validate() in the submit button's onPressed callback; it returns true if all validators returned null.

What if passing the GlobalKey through a complex widget tree is impractical?

Use Form.of(context) from a descendant widget to access the FormState instead of passing the key directly.

Full instructions (SKILL.md)

Source of truth, from flutter/skills.


name: flutter-building-forms description: Builds Flutter forms with validation and user input handling. Use when creating login screens, data entry forms, or any multi-field user input. metadata: model: models/gemini-3.1-pro-preview last_modified: Thu, 12 Mar 2026 22:15:24 GMT


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});

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

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

  @override
  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'),
          ),
        ],
      ),
    );
  }
}