Flutter Form Validation: solved exercise with TextFormField

Flutter Form Validation: solved exercise

If you are looking for Flutter form validation, this solved exercise gives you a practical implementation pattern you can reuse in real projects.

Problem statement

Build a screen with:

  • email field
  • password field
  • field validation rules
  • submit button with user feedback

Flutter solution

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import 'package:flutter/material.dart';

void main() => runApp(const MaterialApp(home: LoginFormPage()));

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

  @override
  State<LoginFormPage> createState() => _LoginFormPageState();
}

class _LoginFormPageState extends State<LoginFormPage> {
  final _formKey = GlobalKey<FormState>();
  final _emailCtrl = TextEditingController();
  final _passCtrl = TextEditingController();

  @override
  void dispose() {
    _emailCtrl.dispose();
    _passCtrl.dispose();
    super.dispose();
  }

  void submit() {
    if (_formKey.currentState!.validate()) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Formulario valido: ${_emailCtrl.text}')),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Formulario Flutter')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Form(
          key: _formKey,
          child: Column(
            children: [
              TextFormField(
                controller: _emailCtrl,
                decoration: const InputDecoration(labelText: 'Email'),
                validator: (value) {
                  if (value == null || value.isEmpty) return 'Email obligatorio';
                  if (!value.contains('@')) return 'Email no valido';
                  return null;
                },
              ),
              TextFormField(
                controller: _passCtrl,
                decoration: const InputDecoration(labelText: 'Password'),
                obscureText: true,
                validator: (value) {
                  if (value == null || value.length < 6) return 'Minimo 6 caracteres';
                  return null;
                },
              ),
              const SizedBox(height: 16),
              ElevatedButton(onPressed: submit, child: const Text('Enviar')),
            ],
          ),
        ),
      ),
    );
  }
}

Expected result

The form submits only when all validation rules are satisfied.

Common mistakes

  • Not using GlobalKey<FormState>.
  • Triggering validation on every keystroke without strategy.
  • Forgetting to dispose controllers.

Practical use

This pattern is the base for login, signup, checkout, and internal business forms.

Guided practice and next step

FAQ

Which widgets are standard for forms in Flutter?

Form with TextFormField and per-field validators.

Where should validation errors live?

Inside field validators with clear and short messages.

Does this scale to bigger forms?

Yes. Extract validators and field widgets as the screen grows.