What is the difference between TextFormField and TextField?

Flutter

Flutter Problem Overview


I am new to Flutter (and Dart) and when trying to build a form to edit an object I searched online for examples and tutorials, and I saw both of these used.

What is the difference between the two? Which one should I use?

Flutter Solutions


Solution 1 - Flutter

> If you making a Form where you require save, reset, or validate > operations- use TextFormField. Else For Simple user input capture > TextField is sufficient.

TextFormField, which integrates with the Form widget.

This is a convenience widget that wraps a TextField widget in a FormField.

A Form ancestor is not required. The Form simply makes it easier to save, reset, or validate multiple fields at once.

To use without a Form, pass a GlobalKey to the constructor and use GlobalKey.currentState to save or reset the form field.

sample:

TextFormField(
  autovalidateMode: AutovalidateMode.always
  decoration: const InputDecoration(
    icon: Icon(Icons.person),
    hintText: 'What do people call you?',
    labelText: 'Name *',
  ),
  onSaved: (String value) {
    // This optional block of code can be used to run
    // code when the user saves the form.
  },
  validator: (String value) {
    return value.contains('@') ? 'Do not use the @ char.' : null;
  },
)

TextField, which is the underlying text field without the Form integration.

The text field calls the onChanged callback whenever the user changes the text in the field. If the user indicates that they are done typing in the field (e.g., by pressing a button on the soft keyboard), the text field calls the onSubmitted callback.

Solution 2 - Flutter

Short answer

If you don't know what you need, then use a TextField. This is the most basic Flutter widget for getting text input from a user. It's the one you should master first.

TextField

Using a TextField is an easy way to allow user input.

TextField(
  decoration: InputDecoration(
    hintText: 'Name'
  ),
);

enter image description here

To get the text that the user entered, you can either get notified every time there is a change like this:

TextField(
  decoration: InputDecoration(
      hintText: 'Name'
  ),
  onChanged: (text) {
    // do something with text
  },
),

Or you can use a TextEditingController, as described here. This will give you access to the text state.

TextFormField

If you find yourself needing to validate user text input before you save it, you might consider using a TextFormField. Imagine something like this:

enter image description here

There are lots of validation checks that you might want to do on a username and password.

Of course, you could still just use a couple TextFields, but TextFormField has extra builtin functionality that will make your life easier. Generally, you will only use a TextFormField when you are using it inside of a Form widget (though that isn't a strict requirement).

Here is a stripped down example from the documentation:

class MyCustomForm extends StatefulWidget {
  @override
  MyCustomFormState createState() {
    return MyCustomFormState();
  }
}

class MyCustomFormState extends State<MyCustomForm> {
  final _formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Column(
        children: <Widget>[
          TextFormField(
            validator: (value) {
              // validation logic
            },
          ),
          RaisedButton(
            child: Text('Submit'),
            onPressed: () {
              if (_formKey.currentState.validate()) {
                // text in form is valid
              }
            },
          ),
        ],
      ),
    );
  }
}

See also

Solution 3 - Flutter

TextField is a simple text field. (you don't care about user input) TextFormField is a text field to be used in a form (you care about user input).

If you don't need to validate TextField. If you need to validate user input, use TextFormField with validator.

Solution 4 - Flutter

TextFormField vs. TextField

TextFormField returns a TextField, but wraps the TextField with extra functionality you can use through a Form and also without (such as reset, validation, save, etc.).

Generally, you want to use TextFormField unless writing boiler-plate code is your thing.

How does TextFormField work? What can it do?

TextFormField extends FormField class, (a StatefulWidget). FormField objects do a special thing when they are instantiated: they look up the widget tree for a Form and register themselves with that Form.

After registration, these FormField widgets can be changed by that parent Form.

Form is also a StatefulWidget. It has a FormState object. FormState can get & set data on any/allFormFields registered to it.

For example to clear the entire form we can call reset() on FormState and FormState will iterate through all child FormFields registered, resetting each FormField to its initialValue (null by default).

Validation is another common use case for putting several FormField like TextFormField inside Form/FormState. This allows multiple fields to be validated with a single validate() call on the Form.

How? FormState has a validate() method that iterates through each registered FormField and calls that FormField's validate() method. Much more convenient calling validate() once on Form than you manually keeping track of all TextField and validating each one separately with custom code.

Details

How does a TextFormField register itself with a Form?

FormField (base class of TextFormField, etc.) make a call within their build() method: Form.of(context)?._register(this);

In English this means: Search up my context hierarchy until we find a Form widget (if any) and register myself with that form.

The ? is in case there is no Form widget parent. The _register call will only be run if there is a Form & FormState somewhere above.

How does Form.of(context)?._register(this) work?

Form & FormState sneakily use InheritedWidget. In FormState.build() you'll see this code:

return WillPopScope(
      onWillPop: widget.onWillPop,
      child: _FormScope( // ← sneaky
        formState: this,
        generation: _generation,
        child: widget.child,
      ),
    );

Looking at _FormScope we see:

class _FormScope extends InheritedWidget

When a parent widget is an InheritedWidget, any child can find that parent using a special "find me a parent of this exact Type" method.

Here's how that "find me" method is used/exposed inside Form as a static method we can call from anywhere:

static FormState of(BuildContext context) {
    final _FormScope scope = context.dependOnInheritedWidgetOfExactType<_FormScope>();
    return scope?._formState;
  }

The naming of that method dependOnInheritedWidgetOfExactType is a bit tricky. It'd be more readable as findInheritedWidgetOfExactType, but it does more than just find. (We can trigger rebuilds of Form through children that have registered as dependOn this FormState).

Summary

TextFormField is the deluxe package, air-conditioned, Bluetooth-connected 8-speaker stereo version of TextField. It includes a lot of common functionality you would use when accepting user-entered information.

Solution 5 - Flutter

(October 2021) I think this might be the most concise and simple explanation about the differences between the two.

From the material library:

> TextField: A material design text field.

> TextFormField: A FormField that contains a TextField.

Similarly, you can wrap FormField around any cupertino input component such as CupertinoTextField

Below is an example about a custom CheckboxFormField, which is a FormField that wraps around the material design component Checkbox:

// A custom CheckboxFormField, which is similar to the built-in TextFormField
bool agreedToTerms = false;
FormField(
  initialValue: false,
  validator: (value) {
    if (value == false) {
      return 'You must agree to the terms of service.';
    }
    return null;
  },
  builder: (FormFieldState formFieldState) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Row(
          children: [
            Checkbox(
              value: agreedToTerms,
              onChanged: (value) {
                // When the value of the checkbox changes,
                // update the FormFieldState so the form is
                // re-validated.
                formFieldState.didChange(value);
                setState(() {
                  agreedToTerms = value;
                });
              },
            ),
            Text(
              'I agree to the terms of service.',
              style: Theme.of(context).textTheme.subtitle1,
            ),
          ],
        ),
        if (!formFieldState.isValid)
          Text(
            formFieldState.errorText ?? "",
            style: Theme.of(context)
                .textTheme
                .caption
                .copyWith(color: Theme.of(context).errorColor),
          ),
      ],
    );
  },
),

Rule of thumb: If your box only have a single input field, just use the raw material input like TextField (FormField is a bit overkill in this case though). If your box has many input fields, you need to wrap each one of them in a FormField, and then integrate all of them to the Form widget to reap the benefits of validating and saving all form fields at once.

Extra tip: If u have a TextField wrapped in a FormField that doesn't allow the user to enter any text such as a CupertinoPickerFormField or a SimpleDialogFormField that offers the user a choice between several options (which is basically a material SimpleDialog widget wrapped in a FormField), just simply use the hintText param of InputDecoration without using TextEditingController to manipulate text. Make the hint text have the same color as the normal input text with hintStyle: const TextStyle(color: Color(0xdd000000)).

This video from Flutter Europe will help you master forms in Flutter in no time.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestioncccView Question on Stackoverflow
Solution 1 - Flutteranmol.majhailView Answer on Stackoverflow
Solution 2 - FlutterSuragchView Answer on Stackoverflow
Solution 3 - FlutterRubens MeloView Answer on Stackoverflow
Solution 4 - FlutterBakerView Answer on Stackoverflow
Solution 5 - FlutterSon NguyenView Answer on Stackoverflow