Popular Searches
Popular Course Categories
Popular Courses

Flutter Forms

Flutter Forms & User Input


Flutter Forms


Flutter Forms provide a structured way to collect, validate, manage, and submit user input. Forms are commonly used for login screens, registration pages, checkout forms, profile editing, feedback forms, search screens, and other data-entry features. Flutter provides the Form, FormField, and TextFormField widgets to build and validate forms. The Form widget groups related form fields and provides methods such as validate(), save(), and reset(). :contentReference[oaicite:0]{index=0}




1. What is a Form in Flutter?


A form is a user interface section that contains one or more input fields where users enter information. Flutter's Form widget acts as a container for grouping form fields and managing their state.


Common Examples of Forms



  • Login form

  • Registration form

  • Contact form

  • Feedback form

  • Profile form

  • Address form

  • Checkout form

  • Job application form

  • Search form

  • Payment information form


Basic Structure


Form(
  child: Column(
    children: [
      TextFormField(),
      ElevatedButton(
        onPressed: () {},
        child: const Text('Submit'),
      ),
    ],
  ),
)



2. Important Flutter Form Widgets










WidgetPurpose
FormGroups multiple form fields and manages form state.
FormFieldRepresents an individual form field with state and validation support.
TextFormFieldProvides a text input field integrated with Form.
TextEditingControllerReads and controls the text entered into a text field.
GlobalKeyProvides access to the form's state for operations such as validation, saving, and resetting.
FocusNodeControls focus between input fields.

TextFormField wraps a text field in a FormField, making it convenient to use validation and other form-related functionality. :contentReference[oaicite:1]{index=1}




3. TextField vs TextFormField


Flutter provides both TextField and TextFormField for text input. TextField is suitable for general text input, while TextFormField integrates with a surrounding Form and is commonly used when validation is required. :contentReference[oaicite:2]{index=2}










FeatureTextFieldTextFormField
Text inputYesYes
Form integrationNo direct Form integrationYes
validator propertyNoYes
onSavedNoYes
Form reset supportNo direct supportYes
Best suited forGeneral inputStructured forms



4. Basic Form Structure


Form(
  child: Column(
    children: [
      TextFormField(),
      TextFormField(),
      ElevatedButton(
        onPressed: () {},
        child: const Text('Submit'),
      ),
    ],
  ),
)

In a real application, the form normally uses a GlobalKey so that the application can validate, save, or reset the form.




5. Using GlobalKey with Form


A GlobalKey provides access to the current FormState. Flutter's documentation recommends a GlobalKey as a straightforward way to access the form state. :contentReference[oaicite:3]{index=3}


final GlobalKey formKey =
    GlobalKey();

Form(
  key: formKey,
  child: Column(
    children: [
      TextFormField(),
    ],
  ),
)




6. Form Validation


Validation checks whether the information entered by the user satisfies the application's requirements. The validator function returns an error message when the input is invalid and returns null when the input is valid. :contentReference[oaicite:4]{index=4}


Example


TextFormField(
  validator: (value) {
    if (value == null || value.isEmpty) {
      return 'Please enter your name';
    }
    return null;
  },
)

How Validation Works



  1. The user enters information.

  2. The user presses the Submit button.

  3. The application calls formKey.currentState!.validate().

  4. Flutter runs the validator for each form field.

  5. If a validator returns an error message, that error is displayed.

  6. If all validators return null, the form is considered valid.




7. Calling validate()


if (formKey.currentState!.validate()) {
  print('Form is valid');
} else {
  print('Form contains errors');
}

The validate() method runs the validators of the form fields and returns true when there are no validation errors. :contentReference[oaicite:5]{index=5}




8. Complete Basic Form Example


import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: const UserFormScreen(),
    );
  }
}

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

  @override
  State createState() => _UserFormScreenState();
}

class _UserFormScreenState extends State {
  final GlobalKey formKey =
      GlobalKey();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('User Form'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(20),
        child: Form(
          key: formKey,
          child: Column(
            children: [
              TextFormField(
                decoration: const InputDecoration(
                  labelText: 'Name',
                  border: OutlineInputBorder(),
                ),
                validator: (value) {
                  if (value == null ||
                      value.trim().isEmpty) {
                    return 'Please enter your name';
                  }
                  return null;
                },
              ),
              const SizedBox(height: 20),
              ElevatedButton(
                onPressed: () {
                  if (formKey.currentState!.validate()) {
                    ScaffoldMessenger.of(context).showSnackBar(
                      const SnackBar(
                        content: Text('Form submitted'),
                      ),
                    );
                  }
                },
                child: const Text('Submit'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}




9. Required Field Validation


Required field validation ensures that a user does not leave an important field empty.


TextFormField(
  decoration: const InputDecoration(
    labelText: 'Full Name',
  ),
  validator: (value) {
    if (value == null || value.trim().isEmpty) {
      return 'Full name is required';
    }
    return null;
  },
)



10. Email Validation


Email fields can be validated before submitting the form.


TextFormField(
  keyboardType: TextInputType.emailAddress,
  decoration: const InputDecoration(
    labelText: 'Email',
  ),
  validator: (value) {
    if (value == null || value.trim().isEmpty) {
      return 'Email is required';
    }

    if (!value.contains('@')) {
      return 'Enter a valid email';
    }

    return null;
  },
)


More Structured Email Check


bool isValidEmail(String email) {
  return RegExp(
    r'^[^@\s]+@[^@\s]+\.[^@\s]+$',
  ).hasMatch(email);
}

TextFormField(
  validator: (value) {
    if (value == null || value.trim().isEmpty) {
      return 'Enter your email';
    }

    if (!isValidEmail(value.trim())) {
      return 'Enter a valid email';
    }

    return null;
  },
)




11. Password Validation


TextFormField(
  obscureText: true,
  decoration: const InputDecoration(
    labelText: 'Password',
  ),
  validator: (value) {
    if (value == null || value.isEmpty) {
      return 'Password is required';
    }

    if (value.length < 8) {
      return 'Password must contain at least 8 characters';
    }

    return null;
  },
)




12. Confirm Password Validation


When a form contains password and confirm-password fields, the second field can be compared with the first field.


final TextEditingController passwordController =
    TextEditingController();

TextFormField(
  controller: passwordController,
  obscureText: true,
  decoration: const InputDecoration(
    labelText: 'Password',
  ),
)

TextFormField(
  obscureText: true,
  decoration: const InputDecoration(
    labelText: 'Confirm Password',
  ),
  validator: (value) {
    if (value == null || value.isEmpty) {
      return 'Please confirm your password';
    }

    if (value != passwordController.text) {
      return 'Passwords do not match';
    }

    return null;
  },
)




13. Phone Number Validation


TextFormField(
  keyboardType: TextInputType.phone,
  decoration: const InputDecoration(
    labelText: 'Phone Number',
  ),
  validator: (value) {
    if (value == null || value.trim().isEmpty) {
      return 'Phone number is required';
    }

    if (value.trim().length < 10) {
      return 'Enter a valid phone number';
    }

    return null;
  },
)




14. TextEditingController in Forms


TextEditingController can be connected to a TextFormField when the application needs to read or modify the field value programmatically.


final TextEditingController nameController =
    TextEditingController();

TextFormField(
  controller: nameController,
  decoration: const InputDecoration(
    labelText: 'Name',
  ),
)


Reading the Value


String name = nameController.text.trim();

When controllers are created by a stateful widget, they should be disposed when no longer needed. :contentReference[oaicite:6]{index=6}




15. Form onSaved Callback


The onSaved callback can be used to store a field's final value when FormState.save() is called.


String name = '';

TextFormField(
  onSaved: (value) {
    name = value?.trim() ?? '';
  },
)


Calling save()


if (formKey.currentState!.validate()) {
  formKey.currentState!.save();
  print(name);
}

FormState.save() invokes the onSaved callback of each form field. :contentReference[oaicite:7]{index=7}




16. Resetting a Form


The reset() method resets the form fields to their initial values and resets their validation state.


formKey.currentState!.reset();

Reset Button


OutlinedButton(
  onPressed: () {
    formKey.currentState!.reset();
  },
  child: const Text('Reset'),
)



17. AutovalidateMode


autovalidateMode controls when validation should automatically occur.







ModeDescription
AutovalidateMode.disabledAutomatic validation is disabled.
AutovalidateMode.alwaysValidation runs automatically.
AutovalidateMode.onUserInteractionValidation responds to user interaction.

Example


TextFormField(
  autovalidateMode:
      AutovalidateMode.onUserInteraction,
  validator: (value) {
    if (value == null || value.isEmpty) {
      return 'Enter your name';
    }
    return null;
  },
)



18. Form-Level onChanged


The Form widget can also receive an onChanged callback when a form field changes.


Form(
  key: formKey,
  onChanged: () {
    print('Form changed');
  },
  child: Column(
    children: [
      TextFormField(),
      TextFormField(),
    ],
  ),
)



19. Handling Different Input Types


Name


TextFormField(
  textCapitalization: TextCapitalization.words,
  decoration: const InputDecoration(
    labelText: 'Full Name',
  ),
)

Email


TextFormField(
  keyboardType: TextInputType.emailAddress,
  decoration: const InputDecoration(
    labelText: 'Email',
  ),
)

Phone


TextFormField(
  keyboardType: TextInputType.phone,
  decoration: const InputDecoration(
    labelText: 'Phone',
  ),
)

Number


TextFormField(
  keyboardType: TextInputType.number,
  decoration: const InputDecoration(
    labelText: 'Age',
  ),
)

Multiline Text


TextFormField(
  maxLines: 5,
  decoration: const InputDecoration(
    labelText: 'Message',
    alignLabelWithHint: true,
  ),
)



20. Password Visibility Control


bool isPasswordVisible = false;

TextFormField(
  obscureText: !isPasswordVisible,
  decoration: InputDecoration(
    labelText: 'Password',
    suffixIcon: IconButton(
      icon: Icon(
        isPasswordVisible
            ? Icons.visibility
            : Icons.visibility_off,
      ),
      onPressed: () {
        setState(() {
          isPasswordVisible = !isPasswordVisible;
        });
      },
    ),
  ),
)




21. Input Formatting


Input formatters can restrict or transform user input before it is processed.


import 'package:flutter/services.dart';

TextFormField(
  keyboardType: TextInputType.number,
  inputFormatters: [
    FilteringTextInputFormatter.digitsOnly,
  ],
  decoration: const InputDecoration(
    labelText: 'PIN Code',
  ),
)


Limit Input Length


TextFormField(
  inputFormatters: [
    LengthLimitingTextInputFormatter(10),
  ],
)



22. Form with Multiple Fields


Form(
  key: formKey,
  child: Column(
    children: [
      TextFormField(
        decoration: const InputDecoration(
          labelText: 'Name',
        ),
      ),
      TextFormField(
        decoration: const InputDecoration(
          labelText: 'Email',
        ),
      ),
      TextFormField(
        decoration: const InputDecoration(
          labelText: 'Phone',
        ),
      ),
      TextFormField(
        obscureText: true,
        decoration: const InputDecoration(
          labelText: 'Password',
        ),
      ),
    ],
  ),
)



23. Complete Registration Form


import 'package:flutter/material.dart';

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

  @override
  State createState() =>
      _RegistrationFormState();
}

class _RegistrationFormState
    extends State {
  final formKey = GlobalKey();

  final nameController = TextEditingController();
  final emailController = TextEditingController();
  final phoneController = TextEditingController();
  final passwordController = TextEditingController();
  final confirmPasswordController = TextEditingController();

  @override
  void dispose() {
    nameController.dispose();
    emailController.dispose();
    phoneController.dispose();
    passwordController.dispose();
    confirmPasswordController.dispose();
    super.dispose();
  }

  void register() {
    if (!formKey.currentState!.validate()) {
      return;
    }

    final name = nameController.text.trim();
    final email = emailController.text.trim();
    final phone = phoneController.text.trim();

    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text('Welcome, $name'),
      ),
    );

    print('Name: $name');
    print('Email: $email');
    print('Phone: $phone');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Registration'),
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(20),
        child: Form(
          key: formKey,
          child: Column(
            children: [
              TextFormField(
                controller: nameController,
                textCapitalization:
                    TextCapitalization.words,
                decoration: const InputDecoration(
                  labelText: 'Full Name',
                  border: OutlineInputBorder(),
                ),
                validator: (value) {
                  if (value == null ||
                      value.trim().isEmpty) {
                    return 'Enter your full name';
                  }
                  return null;
                },
              ),
              const SizedBox(height: 16),
              TextFormField(
                controller: emailController,
                keyboardType:
                    TextInputType.emailAddress,
                decoration: const InputDecoration(
                  labelText: 'Email',
                  border: OutlineInputBorder(),
                ),
                validator: (value) {
                  if (value == null ||
                      value.trim().isEmpty) {
                    return 'Enter your email';
                  }

                  if (!value.contains('@')) {
                    return 'Enter a valid email';
                  }

                  return null;
                },
              ),
              const SizedBox(height: 16),
              TextFormField(
                controller: phoneController,
                keyboardType: TextInputType.phone,
                decoration: const InputDecoration(
                  labelText: 'Phone',
                  border: OutlineInputBorder(),
                ),
                validator: (value) {
                  if (value == null ||
                      value.trim().isEmpty) {
                    return 'Enter your phone number';
                  }

                  if (value.trim().length < 10) {
                    return 'Enter a valid phone number';
                  }

                  return null;
                },
              ),
              const SizedBox(height: 16),
              TextFormField(
                controller: passwordController,
                obscureText: true,
                decoration: const InputDecoration(
                  labelText: 'Password',
                  border: OutlineInputBorder(),
                ),
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Enter a password';
                  }

                  if (value.length < 8) {
                    return 'Password must have at least 8 characters';
                  }

                  return null;
                },
              ),
              const SizedBox(height: 16),
              TextFormField(
                controller: confirmPasswordController,
                obscureText: true,
                decoration: const InputDecoration(
                  labelText: 'Confirm Password',
                  border: OutlineInputBorder(),
                ),
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Confirm your password';
                  }

                  if (value != passwordController.text) {
                    return 'Passwords do not match';
                  }

                  return null;
                },
              ),
              const SizedBox(height: 24),
              SizedBox(
                width: double.infinity,
                child: ElevatedButton(
                  onPressed: register,
                  child: const Text('Register'),
                ),
              ),
              const SizedBox(height: 10),
              OutlinedButton(
                onPressed: () {
                  formKey.currentState!.reset();
                  nameController.clear();
                  emailController.clear();
                  phoneController.clear();
                  passwordController.clear();
                  confirmPasswordController.clear();
                },
                child: const Text('Clear Form'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}




24. Focus Management in Forms


Forms can contain several input fields. Focus management allows the user to move from one field to another efficiently. Flutter provides FocusNode for managing focus. :contentReference[oaicite:8]{index=8}


Creating FocusNodes


final nameFocus = FocusNode();
final emailFocus = FocusNode();

Connecting FocusNode


TextFormField(
  focusNode: nameFocus,
)

Moving Focus


FocusScope.of(context).requestFocus(emailFocus);

Using TextInputAction


TextFormField(
  textInputAction: TextInputAction.next,
  onFieldSubmitted: (_) {
    FocusScope.of(context).requestFocus(emailFocus);
  },
)



25. Disposing FocusNodes


Focus nodes are long-lived objects and should be disposed when they are no longer needed.


@override
void dispose() {
  nameFocus.dispose();
  emailFocus.dispose();
  super.dispose();
}



26. Login Form Example


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

  @override
  State createState() => _LoginFormState();
}

class _LoginFormState extends State {
  final formKey = GlobalKey();

  final emailController = TextEditingController();
  final passwordController = TextEditingController();

  @override
  void dispose() {
    emailController.dispose();
    passwordController.dispose();
    super.dispose();
  }

  void login() {
    if (!formKey.currentState!.validate()) {
      return;
    }

    final email = emailController.text.trim();
    final password = passwordController.text;

    print('Email: $email');
    print('Password: $password');

    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(
        content: Text('Login successful'),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Form(
      key: formKey,
      child: Column(
        children: [
          TextFormField(
            controller: emailController,
            keyboardType: TextInputType.emailAddress,
            decoration: const InputDecoration(
              labelText: 'Email',
            ),
            validator: (value) {
              if (value == null ||
                  value.trim().isEmpty) {
                return 'Enter your email';
              }
              return null;
            },
          ),
          TextFormField(
            controller: passwordController,
            obscureText: true,
            decoration: const InputDecoration(
              labelText: 'Password',
            ),
            validator: (value) {
              if (value == null || value.isEmpty) {
                return 'Enter your password';
              }
              return null;
            },
          ),
          const SizedBox(height: 20),
          ElevatedButton(
            onPressed: login,
            child: const Text('Login'),
          ),
        ],
      ),
    );
  }
}




27. Dropdown Form Field


Forms are not limited to text fields. Selection controls can also participate in form validation.


String? selectedRole;

DropdownButtonFormField(
  decoration: const InputDecoration(
    labelText: 'Role',
    border: OutlineInputBorder(),
  ),
  items: const [
    DropdownMenuItem(
      value: 'student',
      child: Text('Student'),
    ),
    DropdownMenuItem(
      value: 'developer',
      child: Text('Developer'),
    ),
    DropdownMenuItem(
      value: 'designer',
      child: Text('Designer'),
    ),
  ],
  onChanged: (value) {
    selectedRole = value;
  },
  validator: (value) {
    if (value == null) {
      return 'Please select a role';
    }
    return null;
  },
)




28. Checkbox Form Field


Checkboxes can be used for accepting terms, preferences, or other boolean choices.


bool acceptedTerms = false;

CheckboxListTile(
  value: acceptedTerms,
  title: const Text('I agree to the terms'),
  onChanged: (value) {
    setState(() {
      acceptedTerms = value ?? false;
    });
  },
)


Validation Before Submission


if (!acceptedTerms) {
  ScaffoldMessenger.of(context).showSnackBar(
    const SnackBar(
      content: Text('Please accept the terms'),
    ),
  );
  return;
}



29. Date Selection in a Form


A form may also collect a date such as date of birth, appointment date, or delivery date.


DateTime? selectedDate;

Future selectDate(BuildContext context) async {
  final date = await showDatePicker(
    context: context,
    firstDate: DateTime(1950),
    lastDate: DateTime.now(),
    initialDate: DateTime.now(),
  );

  if (date != null) {
    setState(() {
      selectedDate = date;
    });
  }
}




30. Saving Form Data


Form data can be collected after validation.


void saveForm() {
  if (!formKey.currentState!.validate()) {
    return;
  }

  formKey.currentState!.save();

  print('Form data saved');
}


A common flow is:


Validate
   ↓
Save
   ↓
Read/Process Data
   ↓
Send to API or Database
   ↓
Show Success/Error Message



31. Form Submission with API


After validation, form data can be sent to an API.


Future submitForm() async {
  if (!formKey.currentState!.validate()) {
    return;
  }

  final name = nameController.text.trim();
  final email = emailController.text.trim();

  print('Sending data...');
  print('Name: $name');
  print('Email: $email');

  // API request can be performed here.
}


Always validate user input before sending it to a backend service.




32. Handling Form Loading State


When a form performs an asynchronous operation such as an API request, a loading state can prevent repeated submissions.


bool isLoading = false;

Future submitForm() async {
  if (!formKey.currentState!.validate()) {
    return;
  }

  setState(() {
    isLoading = true;
  });

  try {
    await Future.delayed(
      const Duration(seconds: 2),
    );

    print('Form submitted');
  } finally {
    if (mounted) {
      setState(() {
        isLoading = false;
      });
    }
  }
}


Button


ElevatedButton(
  onPressed: isLoading ? null : submitForm,
  child: isLoading
      ? const CircularProgressIndicator()
      : const Text('Submit'),
)



33. Form Error Handling


Validation errors and server errors should be handled separately.









Error TypeExampleHandling
Required fieldName is emptyValidator
Invalid formatEmail is invalidValidator
Password mismatchPasswords differValidator
Network errorRequest failedTry/catch and user message
Server validationEmail already existsDisplay server response



34. Common Form Mistakes


Mistake 1: Not Using a Form Key


Without an appropriate form-state access method, validating the entire form becomes less convenient.


Mistake 2: Forgetting Validators


Collecting input without validation can result in incomplete or invalid data.


Mistake 3: Forgetting dispose()


@override
void dispose() {
  controller.dispose();
  super.dispose();
}

Mistake 4: Creating Controllers Inside build()


Controllers should generally be maintained in the state that owns them rather than recreated during every rebuild.


Mistake 5: Not Handling Loading State


For asynchronous submissions, disable or otherwise guard the submit action while the request is in progress.


Mistake 6: Trusting Client-Side Validation Alone


Client-side validation improves user experience, but backend systems should independently validate data received from clients.




35. Form Best Practices



  • Use Form to group related form fields.

  • Use TextFormField when validation is required.

  • Use GlobalKey when convenient access to form state is needed.

  • Keep validation messages short and understandable.

  • Use appropriate keyboard types for different input fields.

  • Use TextEditingController when direct access to input values is required.

  • Dispose controllers and focus nodes owned by stateful widgets.

  • Use input formatters for input restrictions.

  • Use trim() where leading and trailing spaces should not be significant.

  • Prevent duplicate submissions during asynchronous operations.

  • Do not print passwords or other sensitive information in production logs.

  • Validate important data on the backend as well.

  • Use SingleChildScrollView or another suitable scrolling layout when forms may exceed the available screen height.




36. Responsive Form Layout


Forms should work on different screen sizes. A simple approach is to constrain the form width on larger screens.


Center(
  child: ConstrainedBox(
    constraints: const BoxConstraints(
      maxWidth: 500,
    ),
    child: Padding(
      padding: const EdgeInsets.all(20),
      child: Form(
        key: formKey,
        child: Column(
          children: [
            TextFormField(),
            const SizedBox(height: 16),
            ElevatedButton(
              onPressed: submitForm,
              child: const Text('Submit'),
            ),
          ],
        ),
      ),
    ),
  ),
)



37. Form with Scrollable Content


Long forms can cause overflow on smaller screens or when the keyboard is displayed. A scrollable parent can help the user access all fields.


Scaffold(
  body: SafeArea(
    child: SingleChildScrollView(
      padding: const EdgeInsets.all(20),
      child: Form(
        key: formKey,
        child: Column(
          children: [
            TextFormField(),
            TextFormField(),
            TextFormField(),
            TextFormField(),
            TextFormField(),
          ],
        ),
      ),
    ),
  ),
)



38. Practical Project: Contact Form


Create a contact form containing:



  • Name

  • Email

  • Phone number

  • Subject

  • Message

  • Submit button

  • Reset button


Suggested Validation



  • Name must not be empty.

  • Email must have a valid format.

  • Phone number must contain the required number of digits.

  • Subject must not be empty.

  • Message must contain a minimum number of characters.




39. Practical Exercise


Create a complete Student Registration Form with the following fields:



  1. Student Name

  2. Email

  3. Phone Number

  4. Date of Birth

  5. Course Selection

  6. Password

  7. Confirm Password

  8. Terms and Conditions checkbox

  9. Register button

  10. Reset button


Requirements



  • Use a Form.

  • Use GlobalKey.

  • Use TextFormField for text inputs.

  • Use validators for required fields.

  • Validate email format.

  • Validate password length.

  • Compare password and confirm password.

  • Require terms acceptance.

  • Use a dropdown for course selection.

  • Use a date picker for date of birth.

  • Show a success message after successful validation.

  • Reset the form using reset().

  • Dispose all controllers and focus nodes.




40. Form Lifecycle


User Opens Form
      ↓
User Enters Data
      ↓
Input Validation
      ↓
FormState.validate()
      ↓
Is Data Valid?
   ↙         ↘
 No           Yes
 ↓             ↓
Show Errors   Save Data
               ↓
          Process Data
               ↓
          API/Database
               ↓
        Show Result



41. Important Form Methods







MethodPurpose
validate()Runs validators and checks whether the form is valid.
save()Calls the onSaved callback for form fields.
reset()Resets fields and validation state.

These operations are provided through FormState. :contentReference[oaicite:9]{index=9}




42. Important Form Properties and Callbacks










Property/CallbackPurpose
keyIdentifies the form and provides access to its state when using a GlobalKey.
validatorChecks whether an individual field contains valid input.
onSavedReceives a field's value when the form is saved.
onChangedResponds to changes within the form.
onResetRuns when an individual form field is reset.
autovalidateModeControls automatic validation behavior.



43. Interview Questions


Q1. What is the Form widget in Flutter?


Form is a widget used to group and manage multiple form fields and their state.


Q2. What is TextFormField?


TextFormField is a text input widget integrated with Flutter's form-field system and provides features such as validation and saving.


Q3. Why is GlobalKey used?


It provides a convenient way to access the current form state and call methods such as validate(), save(), and reset().


Q4. What does validator return?


It returns an error message when the input is invalid and null when the input is valid.


Q5. What does validate() return?


It returns true when the form has no validation errors and false when validation errors exist.


Q6. What is FormState.save() used for?


It invokes the onSaved callback for the form fields.


Q7. What does FormState.reset() do?


It resets the form fields and their validation state.


Q8. Why use TextEditingController in a form?


It provides direct access to the current text and allows the application to read, change, or clear the field programmatically.


Q9. What is autovalidateMode?


It controls when form fields automatically run their validation logic.


Q10. Why should controllers be disposed?


Controllers use resources and should be disposed when they are no longer needed.




44. Quick Revision















TaskCode
Create Form KeyGlobalKey()
Create FormForm(key: formKey, child: ...)
Create Form FieldTextFormField()
Validate FormformKey.currentState!.validate()
Save FormformKey.currentState!.save()
Reset FormformKey.currentState!.reset()
Read Controllercontroller.text
Clear Controllercontroller.clear()
Validate Fieldvalidator: (value) { ... }
Auto ValidationautovalidateMode
Save FieldonSaved: (value) { ... }



45. Key Takeaways



  • Flutter provides Form for grouping and managing form fields.

  • TextFormField is useful for text input with form validation.

  • GlobalKey can be used to access the form state.

  • validate() checks all validators in the form.

  • save() invokes field-level onSaved callbacks.

  • reset() resets form fields and their validation state.

  • TextEditingController is useful when direct access to input is required.

  • FocusNode can be used to manage keyboard focus.

  • autovalidateMode controls automatic validation behavior.

  • Input should be validated before processing or submitting it.

  • Client-side validation improves user experience, but backend validation is still important.

  • Controllers and focus nodes owned by stateful widgets should be disposed properly.




46. Official Flutter Resources





47. JustAcademy Flutter Training Resources


Learn more about Flutter development through the following resources:



whatsapp