Flutter
TextField
get value
Flutter development
Flutter tips

How to get the TextField value in flutter

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Reading a TextField value in Flutter looks simple, but the right method depends on interaction style. Some screens need value only on submit, while others need live updates for search and validation. Choosing the correct pattern keeps UI responsive and avoids state-management bugs.

Read Value with TextEditingController

TextEditingController is the most common approach when you need direct read and write access.

dart
1import 'package:flutter/material.dart';
2
3class EmailInput extends StatefulWidget {
4  const EmailInput({super.key});
5
6  
7  State<EmailInput> createState() => _EmailInputState();
8}
9
10class _EmailInputState extends State<EmailInput> {
11  final _controller = TextEditingController();
12
13  
14  void dispose() {
15    _controller.dispose();
16    super.dispose();
17  }
18
19  void _submit() {
20    final value = _controller.text.trim();
21    debugPrint('Submitted: $value');
22  }
23
24  
25  Widget build(BuildContext context) {
26    return Column(
27      children: [
28        TextField(
29          controller: _controller,
30          decoration: const InputDecoration(labelText: 'Email'),
31        ),
32        ElevatedButton(onPressed: _submit, child: const Text('Submit')),
33      ],
34    );
35  }
36}

Dispose the controller in dispose to avoid memory leaks in stateful widgets.

Use onChanged for Live Input Reactions

For real-time search or instant button enablement, use onChanged.

dart
1class SearchBox extends StatefulWidget {
2  const SearchBox({super.key});
3
4  
5  State<SearchBox> createState() => _SearchBoxState();
6}
7
8class _SearchBoxState extends State<SearchBox> {
9  String query = '';
10
11  
12  Widget build(BuildContext context) {
13    return Column(
14      children: [
15        TextField(
16          onChanged: (value) {
17            setState(() {
18              query = value;
19            });
20          },
21          decoration: const InputDecoration(labelText: 'Search'),
22        ),
23        Text('Current query: $query'),
24      ],
25    );
26  }
27}

If typing triggers network requests, add debounce logic so every keystroke does not call the backend.

Use TextFormField for Validation Workflows

When forms include multiple fields and validation, TextFormField with a Form key scales better than manual checks.

dart
1class SignupForm extends StatefulWidget {
2  const SignupForm({super.key});
3
4  
5  State<SignupForm> createState() => _SignupFormState();
6}
7
8class _SignupFormState extends State<SignupForm> {
9  final _formKey = GlobalKey<FormState>();
10  String _username = '';
11
12  void _save() {
13    if (_formKey.currentState!.validate()) {
14      _formKey.currentState!.save();
15      debugPrint('Saved username: $_username');
16    }
17  }
18
19  
20  Widget build(BuildContext context) {
21    return Form(
22      key: _formKey,
23      child: Column(
24        children: [
25          TextFormField(
26            decoration: const InputDecoration(labelText: 'Username'),
27            validator: (value) {
28              if (value == null || value.trim().isEmpty) {
29                return 'Username is required';
30              }
31              return null;
32            },
33            onSaved: (value) => _username = value!.trim(),
34          ),
35          ElevatedButton(onPressed: _save, child: const Text('Create')),
36        ],
37      ),
38    );
39  }
40}

This pattern centralizes validation and keeps submit flow predictable.

Keyboard and Focus Handling

Getting value is only part of UX. Handling submit keys and focus transitions improves usability.

dart
1TextField(
2  textInputAction: TextInputAction.done,
3  onSubmitted: (value) {
4    debugPrint('Keyboard submit: ${value.trim()}');
5    FocusManager.instance.primaryFocus?.unfocus();
6  },
7)

For multi-field forms, use FocusNode and move focus programmatically on next actions.

Keep State Consistent with Architecture

If you use Provider, Riverpod, or Bloc, avoid scattering field state across widgets and global stores without a clear rule. A common strategy is:

  • keep transient typing state local to widget
  • push final validated values to app state on submit

This prevents unnecessary rebuilds and keeps business logic clean.

Prepopulate and Read Initial Values

For edit forms, set the initial value through the controller once, usually in initState, then read updated text on submit.

dart
1
2void initState() {
3  super.initState();
4  _controller.text = widget.initialEmail;
5}

This avoids mismatches between displayed text and stored state in profile-edit screens.

Common Pitfalls

  • Forgetting to dispose TextEditingController in stateful widgets.
  • Running expensive operations on every onChanged event without debounce.
  • Mixing controller and onSaved patterns inconsistently in one form.
  • Validating only at submit time when live guidance is needed.
  • Sending raw untrimmed user input to APIs or storage.

Summary

  • Use TextEditingController when you need direct value access.
  • Use onChanged for live UI updates and search feedback.
  • Use TextFormField with Form for validation-heavy forms.
  • Manage keyboard and focus actions for better mobile UX.
  • Normalize and validate text before storing or sending it.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.