
Flutter Building Forms
Implement Flutter login and data-entry screens with Form, GlobalKey<FormState>, and field validation without breaking state on rebuilds.
Overview
Flutter Building Forms is an agent skill for the Build phase that implements validated Flutter forms using Form, GlobalKey<FormState>, and TextFormField patterns.
Install
npx skills add https://github.com/flutter/skills --skill flutter-building-formsWhat is this skill?
- Form architecture: StatefulWidget host, single final GlobalKey<FormState>—never recreate the key in build
- Field validation workflow with TextFormField and FormState validate/save patterns
- Documents Form.of(context) for deep trees when passing keys is awkward
- Explicit trigger: login screens, data entry, any multi-field user input
- Structured sections: architecture, validation, implement workflow, examples
- 4 documentation sections (architecture, validation, workflow, examples)
Adoption & trust: 8.6k installs on skills.sh; 2.4k GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
Your Flutter login or data-entry UI loses validation state or handles errors inconsistently because the form structure and keys are wrong.
Who is it for?
Indie devs adding auth, checkout, or settings screens in Flutter who want Material-aligned validation in one pass.
Skip if: Web-only React forms, server-side validation design, or apps that have standardized on a third-party form package without Material Form widgets.
When should I use this skill?
Creating login screens, data entry forms, or any multi-field user input in Flutter.
What do I get? / Deliverables
You get a validated form implementation with stable FormState, field-level validators, and a clear submit workflow ready to connect to your API or auth flow.
- Validated Form widget implementation
- Field validators and submit handler pattern
Recommended Skills
Journey fit
Build/frontend is the primary shelf because the skill delivers UI form implementation and validation behavior in the Flutter layer. Frontend covers multi-field user input, Material TextFormField patterns, and submit validation—core mobile client work.
How it compares
Skill package for Flutter Form widgets—not a backend schema validator or a separate form-builder SaaS.
Common Questions / FAQ
Who is flutter-building-forms for?
Solo builders using Flutter for iOS/Android (or multi-platform) who need validated multi-field screens during active product build.
When should I use flutter-building-forms?
During Build frontend work whenever you create login screens, onboarding wizards, or any multi-field data entry in Flutter.
Is flutter-building-forms safe to install?
Review the Security Audits panel on this Prism page; the skill guides UI code only—keep credentials out of client validators and use secure storage for tokens.
SKILL.md
READMESKILL.md - Flutter Building Forms
# Building Validated Forms ## Contents - [Form Architecture](#form-architecture) - [Field Validation](#field-validation) - [Workflow: Implementing a Validated Form](#workflow-implementing-a-validated-form) - [Examples](#examples) ## 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. ```dart 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(