tezvyn:

TextEditingController: Syncing UI and Code for Text Fields

AI-drafted, machine-checkedSource: api.flutter.devbeginner

A TextEditingController is the two-way link between your code and a text field's state. Use it to read user input, set initial text, or move the cursor. A common footgun is forgetting to call `dispose()` on the controller, which leads to memory leaks.

WHY IT EXISTS: Flutter's UI is declarative, meaning you describe what the UI should look like for a given state. But a text field's content is mutable state that changes with every keystroke. A TextEditingController provides an imperative "handle" to this state, letting you interact with it without rebuilding the entire widget tree.

THE MENTAL MODEL: Think of a TextEditingController as the remote control for your TextField. The user can change the channel on the TV itself (by typing), and the remote's display updates. You can also use the remote (your code) to change the channel or text, and the TV will update accordingly. The controller is this two-way communication channel.

HOW IT WORKS: You create a TextEditingController instance inside a StatefulWidget's State object and pass it to a TextField's controller property. The controller holds the text and selection (cursor position) as a TextEditingValue. When the user types, the TextField updates the controller, which then notifies any registered listeners via addListener(). Conversely, if your code changes controller.text or controller.selection, the TextField UI updates automatically. To avoid memory leaks, you must call controller.dispose() in your widget's dispose method.

WHEN TO USE IT: Use a controller whenever you need to read or manipulate a text field's content from your code. This is essential for setting an initial value, clearing the field with a button, reading the text for a search query, validating input as the user types, or programmatically moving the cursor.

WHEN NOT TO USE IT: For simple, synchronous text transformations like forcing input to uppercase or formatting a phone number as it's typed, a TextInputFormatter is often a more direct and efficient solution. Using a controller's listener for this can be clumsy and may lead to infinite loop bugs if not handled carefully.

ONE CANONICAL EXAMPLE: Implementing a character counter for an input field. You attach a controller to the TextField. You also add a listener to the controller. Inside the listener function, you get the length of controller.text and update a separate Text widget to show "120/280 characters". This listener is called on every keystroke, providing real-time feedback to the user.

Read the original → api.flutter.dev

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.