> For the complete documentation index, see [llms.txt](https://flutteruniversity.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://flutteruniversity.gitbook.io/docs/learn-flutter/intermediate/form-handling.md).

# Form Handling

practisingHandling forms correctly is crucial for a good user experience. Flutter provides various widgets and techniques to validate and manage form data.

## 1. `Form` and `FormField` Widgets 📋

The `Form` widget acts as a container for grouping and validating multiple form fields. `FormField` is a single form field.

```dart
Form(
  key: _formKey,
  child: Column(
    children: <Widget>[
      TextFormField(
        validator: (value) {
          if (value == null || value.isEmpty) {
            return 'Please enter some text';
          }
          return null;
        },
      ),
      ElevatedButton(
        onPressed: () {
          if (_formKey.currentState?.validate() ?? false) {
            // If the form is valid, display a Snackbar
            ScaffoldMessenger.of(context)
                .showSnackBar(SnackBar(content: Text('Processing Data')));
          }
        },
        child: Text('Submit'),
      )
    ],
  ),
)
```

## 2. Validation 🛂

Validation is performed by providing a `validator` function to the `FormField`.

```dart
TextFormField(
  validator: (value) {
    if (value == null || value.isEmpty) {
      return 'Please enter some text';
    }
    return null;
  },
)
```

## 3. Saving Form Data 💾

You can save form data by providing a `onSaved` callback to the `FormField`.

```dart
TextFormField(
  onSaved: (value) {
    // Save value
  },
)
```

## 4. Accessing Form Data 🗂️

Access the form data using a `GlobalKey` to access the `Form` state and then call `save` on it.

```dart
final _formKey = GlobalKey<FormState>();

// To save
_formKey.currentState?.save();
```

## 5. Focus and Text Controllers 🎯

Manage focus and text input using `FocusNode` and `TextEditingController`.

```dart
final myController = TextEditingController();

// Use in a TextField
TextField(
  controller: myController,
)
```

## Complete Code & Result

{% tabs %}
{% tab title="Code" %}

```dart
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: FormExample(),
    );
  }
}

class FormExample extends StatefulWidget {
  @override
  _FormExampleState createState() => _FormExampleState();
}

class _FormExampleState extends State<FormExample> {
  final _formKey = GlobalKey<FormState>();
  final _nameController = TextEditingController();
  final _emailController = TextEditingController();
  final _passwordController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Form Handling Example'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Form(
          key: _formKey,
          child: Column(
            children: <Widget>[
              TextFormField(
                controller: _nameController,
                decoration: InputDecoration(labelText: 'Name'),
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Please enter your name';
                  }
                  return null;
                },
              ),
              TextFormField(
                controller: _emailController,
                decoration: InputDecoration(labelText: 'Email'),
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Please enter your email';
                  }
                  // Basic email validation
                  if (!RegExp(r"^[a-zA-Z0-9.]+@[a-zA-Z0-9]+\.[a-zA-Z]+").hasMatch(value)) {
                    return 'Please enter a valid email address';
                  }
                  return null;
                },
              ),
              TextFormField(
                controller: _passwordController,
                decoration: InputDecoration(labelText: 'Password'),
                obscureText: true,
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Please enter your password';
                  }
                  if (value.length < 6) {
                    return 'Password must be at least 6 characters long';
                  }
                  return null;
                },
              ),
              SizedBox(height: 20),
              ElevatedButton(
                onPressed: () {
                  if (_formKey.currentState?.validate() ?? false) {
                    // If the form is valid, navigate to a new screen and display the user data
                    Navigator.push(
                      context,
                      MaterialPageRoute(
                        builder: (context) => UserDataScreen(
                          name: _nameController.text,
                          email: _emailController.text,
                          password: _passwordController.text,
                        ),
                      ),
                    );
                  }
                },
                child: Text('Submit'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class UserDataScreen extends StatelessWidget {
  final String name;
  final String email;
  final String password;

  UserDataScreen({required this.name, required this.email, required this.password});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('User Data'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Text('Name: $name'),
            Text('Email: $email'),
            Text('Password: $password'),
          ],
        ),
      ),
    );
  }
}

```

{% endtab %}

{% tab title="Result" %}

<figure><img src="/files/ppKszqzZrtzInDhT9iLL" alt="" width="450"><figcaption></figcaption></figure>
{% endtab %}
{% endtabs %}

## Assignments 📝

Practice makes perfect! Here are some exercises:

* [ ] Create a form with at least three fields (e.g., name, email, password) and validate the input.
* [ ] Save the data from the form and display it in a new screen.
* [ ] Create a form with some fields that have initial values.
* [ ] Manage focus between text fields using a `FocusNode`.

{% hint style="info" %}
By understanding and practising form handling in Flutter, you’ll be well-equipped to create robust and user-friendly forms in your apps.
{% endhint %}

Next, delve into Networking to learn how to interact with external data sources!


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://flutteruniversity.gitbook.io/docs/learn-flutter/intermediate/form-handling.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
