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- A Flutter project using the Material widget library
How to use flutter-building-forms
- 1.Create a StatefulWidget and its corresponding State class to host the form
- 2.Instantiate `final _formKey = GlobalKey<FormState>();` once in the State class
- 3.Return a Form widget in build() and assign key: _formKey
- 4.Add TextFormField widgets as descendants of the Form
- 5.Write a validator function for each TextFormField, returning an error String or null
- 6.Add a submit button (e.g., ElevatedButton)
- 7.In the button's onPressed, call _formKey.currentState!.validate() and handle the true/false result (submit data or let errors display)
Use cases
- 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
- 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
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.
Return a String error message if input is invalid, or null if the input is valid.
Call _formKey.currentState!.validate() in the submit button's onPressed callback; it returns true if all validators returned null.
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
Forminside aStatefulWidget. - Persist the GlobalKey: Instantiate a
GlobalKey<FormState>exactly once as a final variable within theStateclass. Do not generate a newGlobalKeyinside thebuildmethod; doing so is resource-expensive and destroys the form's state on every rebuild. - Bind the Key: Pass the
GlobalKey<FormState>to thekeyproperty of theFormwidget. This uniquely identifies the form and provides access to theFormStatefor validation and submission. - Alternative Access: If dealing with highly complex widget trees where passing the key is impractical, use
Form.of(context)to access theFormStatefrom 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 eachTextFormField. - Return Error Messages: If the user's input is invalid, return a
Stringcontaining the specific error message. TheFormwill 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
StatefulWidgetand its correspondingStateclass. - 2. Instantiate
final _formKey = GlobalKey<FormState>();in theStateclass. - 3. Return a
Formwidget in thebuildmethod and assignkey: _formKey. - 4. Add
TextFormFieldwidgets as descendants of theForm. - 5. Write a
validatorfunction for eachTextFormField(returnStringon error,nullon success). - 6. Add a submit button (e.g.,
ElevatedButton). - 7. Implement the validation check in the button's
onPressedcallback using_formKey.currentState!.validate().
Validation Decision Logic
When the user triggers the submit action, execute the following conditional logic:
- Call
_formKey.currentState!.validate(). - If
true(Valid): All validators returnednull. Proceed with form submission (e.g., save data, make API call) and display a success indicator (e.g., aSnackBar). - If
false(Invalid): One or more validators returned an error string. TheFormStateautomatically rebuilds the UI to display the error messages. - Feedback Loop: Run validator -> review errors -> fix. The user must adjust their input and resubmit until
validate()returnstrue.
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'),
),
],
),
);
}
}
Related skills
More from flutter/skills and the wider catalog.
flutter-apply-architecture-best-practices
Architect Flutter apps with layered separation of concerns: UI (MVVM), Logic (Domain), and Data (Repository pattern).
flutter-build-responsive-layout
Build Flutter layouts that adapt to any screen size using LayoutBuilder, MediaQuery, and Expanded/Flexible widgets.
flutter-fix-layout-issues
Diagnose and fix Flutter layout errors like overflows and unbounded constraints using constraint violation patterns.
flutter-add-widget-test
Write component-level tests for Flutter widgets using WidgetTester to verify UI rendering and interactions.
flutter-setup-declarative-routing
Configure MaterialApp.router with go_router for advanced URL-based navigation and deep linking.
flutter-add-integration-test
Configure Flutter Driver and convert interactive explorations into permanent integration tests.