Bird
Raised Fist0
Fluttermobile~20 mins

TextFormField in Flutter - Mini App: Build & Ship

Choose your learning style10 modes available
Build: Simple Form Screen
This screen lets the user enter their name using a text input field and submit it. It validates that the name is not empty.
Target UI
-------------------------
| Simple Form Screen    |
|-----------------------|
| Name: [___________]   |
|                       |
|       [Submit]         |
-------------------------
Add a TextFormField for user to enter their name
Validate that the name is not empty when submitting
Show an error message below the field if empty
Add a Submit button that triggers validation
If valid, show a simple dialog with the entered name
Starter Code
Flutter
import 'package:flutter/material.dart';

class SimpleFormScreen extends StatefulWidget {
  @override
  State<SimpleFormScreen> createState() => _SimpleFormScreenState();
}

class _SimpleFormScreenState extends State<SimpleFormScreen> {
  final _formKey = GlobalKey<FormState>();
  final _nameController = TextEditingController();

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Simple Form Screen')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Form(
          key: _formKey,
          child: Column(
            children: [
              // TODO: Add TextFormField here
              // TODO: Add Submit button here
            ],
          ),
        ),
      ),
    );
  }
}
Task 1
Task 2
Task 3
Task 4
Solution
Flutter
import 'package:flutter/material.dart';

class SimpleFormScreen extends StatefulWidget {
  @override
  State<SimpleFormScreen> createState() => _SimpleFormScreenState();
}

class _SimpleFormScreenState extends State<SimpleFormScreen> {
  final _formKey = GlobalKey<FormState>();
  final _nameController = TextEditingController();

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

  void _submit() {
    if (_formKey.currentState!.validate()) {
      showDialog(
        context: context,
        builder: (context) => AlertDialog(
          title: Text('Hello'),
          content: Text('Your name is: ${_nameController.text}'),
          actions: [
            TextButton(
              onPressed: () => Navigator.of(context).pop(),
              child: Text('OK'),
            ),
          ],
        ),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Simple Form Screen')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Form(
          key: _formKey,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              TextFormField(
                controller: _nameController,
                decoration: InputDecoration(
                  labelText: 'Name',
                  border: OutlineInputBorder(),
                ),
                validator: (value) {
                  if (value == null || value.trim().isEmpty) {
                    return 'Please enter your name';
                  }
                  return null;
                },
              ),
              SizedBox(height: 20),
              Center(
                child: ElevatedButton(
                  onPressed: _submit,
                  child: Text('Submit'),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

We use a Form widget with a GlobalKey to manage validation. The TextFormField has a validator function that checks if the input is empty and returns an error message if so. The Submit button calls _formKey.currentState!.validate() to trigger validation. If valid, it shows a dialog with the entered name. We also use a TextEditingController to get the text input value.

Final Result
Completed Screen
-------------------------
| Simple Form Screen    |
|-----------------------|
| Name: [John Doe    ]  |
|                       |
|       [Submit]         |
-------------------------
User types their name in the text field
If user taps Submit with empty field, error message appears below the field
If user taps Submit with valid name, a dialog pops up showing 'Your name is: [name]'
User can close the dialog by tapping OK
Stretch Goal
Add a Clear button that clears the text field when tapped
💡 Hint
Add an IconButton inside the TextFormField's suffixIcon that calls _nameController.clear()

Practice

(1/5)
1. What is the main purpose of a TextFormField widget in Flutter?
easy
A. To let users type and edit text input
B. To display images in the app
C. To create buttons for user interaction
D. To navigate between screens

Solution

  1. Step 1: Understand the widget's role

    TextFormField is designed to accept text input from users.
  2. Step 2: Compare with other widget functions

    Other widgets like Image or ElevatedButton serve different purposes, not text input.
  3. Final Answer:

    To let users type and edit text input -> Option A
  4. Quick Check:

    Text input = TextFormField [OK]
Hint: TextFormField is for typing text only [OK]
Common Mistakes:
  • Confusing TextFormField with buttons or images
  • Thinking it handles navigation
  • Assuming it only displays static text
2. Which of the following is the correct way to add a label inside a TextFormField?
easy
A. TextFormField(labelText: 'Name')
B. TextFormField(hint: 'Name')
C. TextFormField(decoration: InputDecoration(labelText: 'Name'))
D. TextFormField(text: 'Name')

Solution

  1. Step 1: Recall how decoration works

    Labels and hints are added inside the decoration property using InputDecoration.
  2. Step 2: Check each option's syntax

    Only TextFormField(decoration: InputDecoration(labelText: 'Name')) correctly uses decoration: InputDecoration(labelText: 'Name').
  3. Final Answer:

    TextFormField(decoration: InputDecoration(labelText: 'Name')) -> Option C
  4. Quick Check:

    Label goes inside decoration [OK]
Hint: Use decoration with InputDecoration for labels [OK]
Common Mistakes:
  • Putting labelText directly on TextFormField
  • Using hint instead of labelText for labels
  • Confusing text property with label
3. What will happen when the following Flutter code runs and the user submits an empty form?
final _formKey = GlobalKey<FormState>();

Form(
  key: _formKey,
  child: TextFormField(
    validator: (value) {
      if (value == null || value.isEmpty) {
        return 'Please enter text';
      }
      return null;
    },
  ),
)
medium
A. The form submits successfully without errors
B. The app crashes due to missing onSaved callback
C. The TextFormField clears automatically
D. The validator returns 'Please enter text' and shows an error

Solution

  1. Step 1: Understand validator behavior

    The validator checks if the input is empty and returns an error message if true.
  2. Step 2: Analyze empty input case

    If the user submits empty text, the validator returns 'Please enter text', showing an error below the field.
  3. Final Answer:

    The validator returns 'Please enter text' and shows an error -> Option D
  4. Quick Check:

    Empty input triggers validator error [OK]
Hint: Empty input triggers validator error message [OK]
Common Mistakes:
  • Assuming form submits without validation
  • Thinking missing onSaved causes crash
  • Believing TextFormField clears on submit
4. Identify the error in this Flutter code snippet using TextFormField:
TextFormField(
  validator: (value) {
    if (value.isEmpty) {
      return 'Required';
    }
    return null;
  },
)
medium
A. Validator should return a boolean, not a string
B. Missing null check for value before calling isEmpty
C. TextFormField requires an onChanged callback
D. Validator cannot be used without a Form widget

Solution

  1. Step 1: Check validator parameter type

    The validator receives a nullable String? value, so it can be null.
  2. Step 2: Identify missing null check

    The code calls value.isEmpty without checking if value is null, causing a runtime error.
  3. Final Answer:

    Missing null check for value before calling isEmpty -> Option B
  4. Quick Check:

    Always check for null before isEmpty [OK]
Hint: Check for null before using isEmpty on value [OK]
Common Mistakes:
  • Ignoring nullable value in validator
  • Expecting validator to return boolean
  • Thinking onChanged is mandatory
5. You want to create a form with a TextFormField that only accepts numbers and shows a hint 'Enter age'. Which code snippet correctly implements this?
hard
A. TextFormField( keyboardType: TextInputType.number, decoration: InputDecoration(hintText: 'Enter age'), validator: (value) { if (value == null || value.isEmpty) return 'Age required'; if (int.tryParse(value) == null) return 'Enter a valid number'; return null; }, )
B. TextFormField( keyboardType: TextInputType.text, decoration: InputDecoration(labelText: 'Enter age'), validator: (value) => null, )
C. TextFormField( decoration: InputDecoration(hintText: 'Enter age'), validator: (value) { if (value!.isEmpty) return 'Age required'; return null; }, )
D. TextFormField( keyboardType: TextInputType.number, decoration: InputDecoration(hintText: 'Age'), validator: (value) { if (value == null) return 'Age required'; return null; }, )

Solution

  1. Step 1: Identify required properties for numeric input with hint

    The correct implementation requires keyboardType: TextInputType.number, decoration: InputDecoration(hintText: 'Enter age'), and a validator checking for null/empty and valid integer parse.
  2. Step 2: Verify validator handles all cases

    Validator must return error for null, empty, or non-numeric input using if (value == null || value.isEmpty) and int.tryParse(value) == null.
  3. Final Answer:

    TextFormField( keyboardType: TextInputType.number, decoration: InputDecoration(hintText: 'Enter age'), validator: (value) { if (value == null || value.isEmpty) return 'Age required'; if (int.tryParse(value) == null) return 'Enter a valid number'; return null; }, ) -> Option A
  4. Quick Check:

    number keyboard + exact hint + null/empty/parse validator [OK]
Hint: Use keyboardType.number and validate parsing for numbers [OK]
Common Mistakes:
  • Using text keyboard for numeric input
  • Not validating numeric format
  • Confusing hintText and labelText
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard