← All courses

Forms, Input & Validation

🗓 May 31, 2026 ⏱ 2 min read

TextField and controllers

The basic input widget is TextField. To read or change its value you usually attach a TextEditingController.

final nameController = TextEditingController();

TextField(
  controller: nameController,
  decoration: const InputDecoration(
    labelText: 'Name',
    border: OutlineInputBorder(),
  ),
)

// read the value later:
print(nameController.text);

Always dispose() controllers in your State’s dispose method to avoid leaks.

The Form widget for validation

For multiple fields with validation, wrap them in a Form with a GlobalKey and use TextFormField, which adds a validator.

final _formKey = GlobalKey<FormState>();

Form(
  key: _formKey,
  child: Column(children: [
    TextFormField(
      decoration: const InputDecoration(labelText: 'Email'),
      validator: (value) {
        if (value == null || !value.contains('@')) {
          return 'Enter a valid email';
        }
        return null;   // null means valid
      },
    ),
    ElevatedButton(
      onPressed: () {
        if (_formKey.currentState!.validate()) {
          // all validators passed -> submit
        }
      },
      child: const Text('Submit'),
    ),
  ]),
)

validate() runs every field’s validator and shows error messages automatically — a validator returns null when valid, or an error string when not.

Input types and formatting

TextFormField(
  keyboardType: TextInputType.emailAddress,
  obscureText: true,                 // for passwords
  inputFormatters: [FilteringTextInputFormatter.digitsOnly], // numbers only
)

Managing focus

Use FocusNode and textInputAction to move from one field to the next when the user taps the keyboard’s “next” button — a small touch that greatly improves form UX.

Common mistakes

  • Forgetting to dispose controllers (memory leaks).
  • Not wrapping fields in a Form when you need validation.
  • Setting the wrong keyboardType (e.g. numbers vs email).
Summary: Use TextField + TextEditingController for input, and a Form with TextFormField validators for multi-field validation (validate() checks them all). Pick the right keyboardType and dispose controllers.