What is TextEditingController?
TextEditingController is a controller that manages the text being edited in a TextField or TextFormField. It allows you to programmatically read, modify, and listen to changes in the text input. Using a controller gives you fine‑grained control over the text field, such as setting initial values, clearing the text, or reacting to each keystroke.
Creating and Disposing a Controller
Always create the controller in initState and dispose it in dispose to prevent memory leaks. Never create a controller directly inside the build method because it would be recreated on every rebuild, leading to performance issues and unexpected behavior.
Reading the Text
Use the .text property to get the current content of the text field. This is useful when you need to retrieve the user's input (e.g., on button press).
Setting the Text Programmatically
To set or change the text, assign a new string to the .text property. The text field will update automatically. This is useful for pre‑filling fields, resetting them, or reflecting external changes.
Listening to Text Changes
You can listen to changes in the text by adding a listener to the controller. The listener is called whenever the text changes (every keystroke). This is useful for implementing live validation, search‑as‑you‑type, or updating other parts of the UI.
Remember to remove the listener in dispose if you added it manually, but if you simply use addListener, the controller will manage the listener list; however, it's still good practice to remove it if you stop needing it. In the example above, it's fine to leave it as the controller will be disposed anyway.
Using with FocusNode
Often you combine TextEditingController with a FocusNode to control focus and text together. For example, you might want to clear the text when the field loses focus, or request focus after setting a value.
Selection and Cursor Control
TextEditingController also exposes the selection (cursor position and selected range). You can read and modify it using _controller.selection. For example, to move the cursor to the end after setting a new value:
Common Mistakes
- Not disposing the controller: This leads to memory leaks, especially in stateful widgets that are frequently created/destroyed.
- Creating the controller in
build: The controller will be recreated on every rebuild, causing loss of text, listeners, and performance issues.
- Creating the controller in
- Setting
.textwithout usingsetState: Changing.textdoes not automatically rebuild the widget; the text field updates internally, but if you need to reflect the change elsewhere, you may need to callsetState.
- Setting
- Forgetting to add a listener in
initStateand remove it indispose: If you add a listener manually, make sure to remove it indisposeusing_controller.removeListener.
- Forgetting to add a listener in
Best Practices
- Always create the controller in
initStateand dispose indispose.
- Always create the controller in
- Use
_controller.clear()to reset the field.
- Use
- For real‑time validation, add a listener and call
setStateto update error messages.
- For real‑time validation, add a listener and call
- When setting text programmatically, consider moving the cursor to the end for better UX.
- Combine with
FocusNodeto manage focus and text together.
- Combine with
Key Takeaways
TextEditingControllergives you programmatic control overTextFieldandTextFormField.
- Create in
initState, dispose indispose.
- Create in
- Use
.textto read or write the content.
- Use
- Add a listener with
addListenerto react to changes.
- Add a listener with
- Combine with
FocusNodefor focus management.
- Combine with
- Always dispose to avoid memory leaks.