EditableText class
A basic text input field.
This widget interacts with the TextInput service to let the user edit the text it contains. It also provides scrolling, selection, and cursor movement.
The EditableText widget is a low-level widget that is intended as a building block for custom widget sets. For a complete user experience, consider using a TextField or CupertinoTextField.
Handling User Input
Currently the user may change the text this widget contains via keyboard or the text selection menu. When the user inserted or deleted text, you will be notified of the change and get a chance to modify the new text value:
-
The inputFormatters will be first applied to the user input.
-
The controller's TextEditingController.value will be updated with the formatted result, and the controller's listeners will be notified.
-
The onChanged callback, if specified, will be called last.
Input Actions
A TextInputAction can be provided to customize the appearance of the action button on the soft keyboard for Android and iOS. The default action is TextInputAction.done.
Many TextInputActions are common between Android and iOS. However, if a textInputAction is provided that is not supported by the current platform in debug mode, an error will be thrown when the corresponding EditableText receives focus. For example, providing iOS's "emergencyCall" action when running on an Android device will result in an error when in debug mode. In release mode, incompatible TextInputActions are replaced either with "unspecified" on Android, or "default" on iOS. Appropriate textInputActions can be chosen by checking the current platform and then selecting the appropriate action.
Lifecycle
Upon completion of editing, like pressing the "done" button on the keyboard, two actions take place:
1st: Editing is finalized. The default behavior of this step includes an invocation of onChanged. That default behavior can be overridden. See onEditingComplete for details.
2nd: onSubmitted is invoked with the user's input value.
onSubmitted can be used to manually move focus to another input widget when a user finishes with the currently focused input widget.
When the widget has focus, it will prevent itself from disposing via AutomaticKeepAliveClientMixin.wantKeepAlive in order to avoid losing the selection. Removing the focus will allow it to be disposed.
Rather than using this widget directly, consider using TextField, which is a full-featured, material-design text input field with placeholder text, labels, and Form integration.
Text Editing Intents and Their Default Actions
This widget provides default Actions for handling common text editing Intents such as deleting, copying and pasting in the text field. These Actions can be directly invoked using Actions.invoke or the Actions.maybeInvoke method. The default text editing keyboard Shortcuts, typically declared in DefaultTextEditingShortcuts, also use these Intents and Actions to perform the text editing operations they are bound to.
The default handling of a specific Intent can be overridden by placing an Actions widget above this widget. See the Action class and the Action.overridable constructor for more information on how a pre-defined overridable Action can be overridden.
Intents for Deleting Text and Their Default Behavior
Intent Class | Default Behavior when there's selected text | Default Behavior when there is a caret (The selection is TextSelection.collapsed) |
---|---|---|
DeleteCharacterIntent | Deletes the selected text | Deletes the user-perceived character before or after the caret location. |
DeleteToNextWordBoundaryIntent | Deletes the selected text and the word before/after the selection's TextSelection.extent position | Deletes from the caret location to the previous or the next word boundary |
DeleteToLineBreakIntent | Deletes the selected text, and deletes to the start/end of the line from the selection's TextSelection.extent position | Deletes from the caret location to the logical start or end of the current line |
Intents for Moving the Caret
Intent Class | Default Behavior when there's selected text | Default Behavior when there is a caret (TextSelection.collapsed) |
---|---|---|
ExtendSelectionByCharacterIntent(collapseSelection: true ) |
Collapses the selection to the logical start/end of the selection | Moves the caret past the user-perceived character before or after the current caret location. |
ExtendSelectionToNextWordBoundaryIntent(collapseSelection: true ) |
Collapses the selection to the word boundary before/after the selection's TextSelection.extent position | Moves the caret to the previous/next word boundary. |
ExtendSelectionToNextWordBoundaryOrCaretLocationIntent(collapseSelection: true ) |
Collapses the selection to the word boundary before/after the selection's TextSelection.extent position, or TextSelection.base, whichever is closest in the given direction | Moves the caret to the previous/next word boundary. |
ExtendSelectionToLineBreakIntent(collapseSelection: true ) |
Collapses the selection to the start/end of the line at the selection's TextSelection.extent position | Moves the caret to the start/end of the current line . |
ExtendSelectionVerticallyToAdjacentLineIntent(collapseSelection: true ) |
Collapses the selection to the position closest to the selection's TextSelection.extent, on the previous/next adjacent line | Moves the caret to the closest position on the previous/next adjacent line. |
ExtendSelectionVerticallyToAdjacentPageIntent(collapseSelection: true ) |
Collapses the selection to the position closest to the selection's TextSelection.extent, on the previous/next adjacent page | Moves the caret to the closest position on the previous/next adjacent page. |
ExtendSelectionToDocumentBoundaryIntent(collapseSelection: true ) |
Collapses the selection to the start/end of the document | Moves the caret to the start/end of the document. |
Intents for Extending the Selection
Intent Class | Default Behavior when there's selected text | Default Behavior when there is a caret (TextSelection.collapsed) |
---|---|---|
ExtendSelectionByCharacterIntent(collapseSelection: false ) |
Moves the selection's TextSelection.extent past the user-perceived character before/after it | |
ExtendSelectionToNextWordBoundaryIntent(collapseSelection: false ) |
Moves the selection's TextSelection.extent to the previous/next word boundary | |
ExtendSelectionToNextWordBoundaryOrCaretLocationIntent(collapseSelection: false ) |
Moves the selection's TextSelection.extent to the previous/next word boundary, or TextSelection.base whichever is closest in the given direction | Moves the selection's TextSelection.extent to the previous/next word boundary. |
ExtendSelectionToLineBreakIntent(collapseSelection: false ) |
Moves the selection's TextSelection.extent to the start/end of the line | |
ExtendSelectionVerticallyToAdjacentLineIntent(collapseSelection: false ) |
Moves the selection's TextSelection.extent to the closest position on the previous/next adjacent line | |
ExtendSelectionVerticallyToAdjacentPageIntent(collapseSelection: false ) |
Moves the selection's TextSelection.extent to the closest position on the previous/next adjacent page | |
ExtendSelectionToDocumentBoundaryIntent(collapseSelection: false ) |
Moves the selection's TextSelection.extent to the start/end of the document | |
SelectAllTextIntent | Selects the entire document |
Other Intents
Intent Class | Default Behavior |
---|---|
DoNothingAndStopPropagationTextIntent | Does nothing in the input field, and prevents the key event from further propagating in the widget tree. |
ReplaceTextIntent | Replaces the current TextEditingValue in the input field's TextEditingController, and triggers all related user callbacks and TextInputFormatters. |
UpdateSelectionIntent | Updates the current selection in the input field's TextEditingController, and triggers the onSelectionChanged callback. |
CopySelectionTextIntent | Copies or cuts the selected text into the clipboard |
PasteTextIntent | Inserts the current text in the clipboard after the caret location, or replaces the selected text if the selection is not collapsed. |
Text Editing Shortcuts
It's also possible to directly remap keyboard shortcuts to new Intents by inserting a Shortcuts widget above this in the widget tree. When using WidgetsApp, the large set of default text editing keyboard shortcuts are declared near the top of the widget tree in DefaultTextEditingShortcuts, and any Shortcuts widget between it and this EditableText will override those defaults.
Interactions Between Shortcuts and Text Input
Shortcuts prevent text input fields from receiving their keystrokes as text input. For example, placing a Shortcuts widget in the widget tree above a text input field and creating a shortcut for LogicalKeyboardKey.keyA will prevent the field from receiving that key as text input. In other words, typing key "A" into the field will trigger the shortcut and will not insert a letter "a" into the field.
This happens because of the way that key strokes are handled in Flutter. When a keystroke is received in Flutter's engine, it first gives the framework the opportunity to handle it as a raw key event through SystemChannels.keyEvent. This is what Shortcuts listens to indirectly through its FocusNode. If it is not handled, then it will proceed to try handling it as text input through SystemChannels.textInput, which is what EditableTextState listens to through TextInputClient.
This behavior, where a shortcut prevents text input into some field, can be overridden by using another Shortcuts widget lower in the widget tree and mapping the desired key stroke(s) to DoNothingAndStopPropagationIntent. The key event will be reported as unhandled by the framework and will then be sent as text input as usual.
Gesture Events Handling
When rendererIgnoresPointer is false (the default), this widget provides rudimentary, platform-agnostic gesture handling for user actions such as tapping, long-pressing, and scrolling.
To provide more complete gesture handling, including double-click to select a word, drag selection, and platform-specific handling of gestures such as long presses, consider setting rendererIgnoresPointer to true and using TextSelectionGestureDetectorBuilder.
Keep the caret visible when focused
When focused, this widget will make attempts to keep the text area and its
caret (even when showCursor is false
) visible, on these occasions:
- When the user focuses this text field and it is not readOnly.
- When the user changes the selection of the text field, or changes the text when the text field is not readOnly.
- When the virtual keyboard pops up.
Scrolling Considerations
If this EditableText is not a descendant of Scaffold and is being used within a Scrollable or nested Scrollables, consider placing a ScrollNotificationObserver above the root Scrollable that contains this EditableText to ensure proper scroll coordination for EditableText and its components like TextSelectionOverlay.
Troubleshooting Common Accessibility Issues
Customizing User Input Accessibility Announcements
To customize user input accessibility announcements triggered by text changes, use SemanticsService.announce to make the desired accessibility announcement.
On iOS, the on-screen keyboard may announce the most recent input
incorrectly when a TextInputFormatter inserts a thousands separator to
a currency value text field. The following example demonstrates how to
suppress the default accessibility announcements by always announcing
the content of the text field as a US currency value (the \$
inserts
a dollar sign, the $newText
interpolates the newText
variable):
onChanged: (String newText) {
if (newText.isNotEmpty) {
SemanticsService.announce('\$$newText', Directionality.of(context));
}
}
See also:
- Inheritance
-
- Object
- DiagnosticableTree
- Widget
- StatefulWidget
- EditableText
Constructors
-
EditableText({Key? key, required TextEditingController controller, required FocusNode focusNode, bool readOnly = false, String obscuringCharacter = '•', bool obscureText = false, bool autocorrect = true, SmartDashesType? smartDashesType, SmartQuotesType? smartQuotesType, bool enableSuggestions = true, required TextStyle style, StrutStyle? strutStyle, required Color cursorColor, required Color backgroundCursorColor, TextAlign textAlign = TextAlign.start, TextDirection? textDirection, Locale? locale, @Deprecated('Use textScaler instead. ' 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' 'This feature was deprecated after v3.12.0-2.0.pre.') double? textScaleFactor, TextScaler? textScaler, int? maxLines = 1, int? minLines, bool expands = false, bool forceLine = true, TextHeightBehavior? textHeightBehavior, TextWidthBasis textWidthBasis = TextWidthBasis.parent, bool autofocus = false, bool? showCursor, bool showSelectionHandles = false, Color? selectionColor, TextSelectionControls? selectionControls, TextInputType? keyboardType, TextInputAction? textInputAction, TextCapitalization textCapitalization = TextCapitalization.none, ValueChanged<
String> ? onChanged, VoidCallback? onEditingComplete, ValueChanged<String> ? onSubmitted, AppPrivateCommandCallback? onAppPrivateCommand, SelectionChangedCallback? onSelectionChanged, VoidCallback? onSelectionHandleTapped, Object groupId = EditableText, TapRegionCallback? onTapOutside, List<TextInputFormatter> ? inputFormatters, MouseCursor? mouseCursor, bool rendererIgnoresPointer = false, double cursorWidth = 2.0, double? cursorHeight, Radius? cursorRadius, bool cursorOpacityAnimates = false, Offset? cursorOffset, bool paintCursorAboveText = false, BoxHeightStyle selectionHeightStyle = ui.BoxHeightStyle.tight, BoxWidthStyle selectionWidthStyle = ui.BoxWidthStyle.tight, EdgeInsets scrollPadding = const EdgeInsets.all(20.0), Brightness keyboardAppearance = Brightness.light, DragStartBehavior dragStartBehavior = DragStartBehavior.start, bool? enableInteractiveSelection, ScrollController? scrollController, ScrollPhysics? scrollPhysics, Color? autocorrectionTextRectColor, @Deprecated('Use `contextMenuBuilder` instead. ' 'This feature was deprecated after v3.3.0-0.5.pre.') ToolbarOptions? toolbarOptions, Iterable<String> ? autofillHints = const <String>[], AutofillClient? autofillClient, Clip clipBehavior = Clip.hardEdge, String? restorationId, ScrollBehavior? scrollBehavior, bool scribbleEnabled = true, bool enableIMEPersonalizedLearning = true, ContentInsertionConfiguration? contentInsertionConfiguration, EditableTextContextMenuBuilder? contextMenuBuilder, SpellCheckConfiguration? spellCheckConfiguration, TextMagnifierConfiguration magnifierConfiguration = TextMagnifierConfiguration.disabled, UndoHistoryController? undoController}) - Creates a basic text input control.
Properties
- autocorrect → bool
-
Whether to enable autocorrection.
final
- autocorrectionTextRectColor → Color?
-
The color to use when painting the autocorrection Rect.
final
- autofillClient → AutofillClient?
-
The AutofillClient that controls this input field's autofill behavior.
final
-
autofillHints
→ Iterable<
String> ? -
A list of strings that helps the autofill service identify the type of this
text input.
final
- autofocus → bool
-
Whether this text field should focus itself if nothing else is already
focused.
final
- backgroundCursorColor → Color
-
The color to use when painting the background cursor aligned with the text
while rendering the floating cursor.
final
- clipBehavior → Clip
-
The content will be clipped (or not) according to this option.
final
- contentInsertionConfiguration → ContentInsertionConfiguration?
-
Configuration of handler for media content inserted via the system input
method.
final
- contextMenuBuilder → EditableTextContextMenuBuilder?
-
Builds the text selection toolbar when requested by the user.
final
- controller → TextEditingController
-
Controls the text being edited.
final
- cursorColor → Color
-
The color to use when painting the cursor.
final
- cursorHeight → double?
-
How tall the cursor will be.
final
- cursorOffset → Offset?
-
The offset that is used, in pixels, when painting the cursor on screen.
final
- cursorOpacityAnimates → bool
-
Whether the cursor will animate from fully transparent to fully opaque
during each cursor blink.
final
- cursorRadius → Radius?
-
How rounded the corners of the cursor should be.
final
- cursorWidth → double
-
How thick the cursor will be.
final
- dragStartBehavior → DragStartBehavior
-
Determines the way that drag start behavior is handled.
final
- enableIMEPersonalizedLearning → bool
-
Whether to enable that the IME update personalized data such as typing
history and user dictionary data.
final
- enableInteractiveSelection → bool
-
Whether to enable user interface affordances for changing the
text selection.
final
- enableSuggestions → bool
-
Whether to show input suggestions as the user types.
final
- expands → bool
-
Whether this widget's height will be sized to fill its parent.
final
- focusNode → FocusNode
-
Controls whether this widget has keyboard focus.
final
- forceLine → bool
-
Whether the text will take the full width regardless of the text width.
final
- groupId → Object
-
The group identifier for the TextFieldTapRegion of this text field.
final
- hashCode → int
-
The hash code for this object.
no setterinherited
-
inputFormatters
→ List<
TextInputFormatter> ? -
Optional input validation and formatting overrides.
final
- key → Key?
-
Controls how one widget replaces another widget in the tree.
finalinherited
- keyboardAppearance → Brightness
-
The appearance of the keyboard.
final
- keyboardType → TextInputType
-
The type of keyboard to use for editing the text.
final
- locale → Locale?
-
Used to select a font when the same Unicode character can
be rendered differently, depending on the locale.
final
- magnifierConfiguration → TextMagnifierConfiguration
-
The configuration for the magnifier to use with selections in this text
field.
final
- maxLines → int?
-
The maximum number of lines to show at one time, wrapping if necessary.
final
- minLines → int?
-
The minimum number of lines to occupy when the content spans fewer lines.
final
- mouseCursor → MouseCursor?
-
The cursor for a mouse pointer when it enters or is hovering over the
widget.
final
- obscureText → bool
-
Whether to hide the text being edited (e.g., for passwords).
final
- obscuringCharacter → String
-
Character used for obscuring text if obscureText is true.
final
- onAppPrivateCommand → AppPrivateCommandCallback?
-
This is used to receive a private command from the input method.
final
-
onChanged
→ ValueChanged<
String> ? -
Called when the user initiates a change to the TextField's
value: when they have inserted or deleted text.
final
- onEditingComplete → VoidCallback?
-
Called when the user submits editable content (e.g., user presses the "done"
button on the keyboard).
final
- onSelectionChanged → SelectionChangedCallback?
-
Called when the user changes the selection of text (including the cursor
location).
final
- onSelectionHandleTapped → VoidCallback?
-
A callback that's optionally invoked when a selection handle is tapped.
final
-
onSubmitted
→ ValueChanged<
String> ? -
Called when the user indicates that they are done editing the text in the
field.
final
- onTapOutside → TapRegionCallback?
-
Called for each tap that occurs outside of theTextFieldTapRegion group
when the text field is focused.
final
- paintCursorAboveText → bool
-
If the cursor should be painted on top of the text or underneath it.
final
- readOnly → bool
-
Whether the text can be changed.
final
- rendererIgnoresPointer → bool
-
Whether the caller will provide gesture handling (true), or if the
EditableText is expected to handle basic gestures (false).
final
- restorationId → String?
-
Restoration ID to save and restore the scroll offset of the
EditableText.
final
- runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
- scribbleEnabled → bool
-
Whether iOS 14 Scribble features are enabled for this widget.
final
- scrollBehavior → ScrollBehavior?
-
A ScrollBehavior that will be applied to this widget individually.
final
- scrollController → ScrollController?
-
The ScrollController to use when vertically scrolling the input.
final
- scrollPadding → EdgeInsets
-
Configures the padding for the edges surrounding a Scrollable when the
text field scrolls into view.
final
- scrollPhysics → ScrollPhysics?
-
The ScrollPhysics to use when vertically scrolling the input.
final
- selectionColor → Color?
-
The color to use when painting the selection.
final
- selectionControls → TextSelectionControls?
-
Optional delegate for building the text selection handles.
final
- selectionEnabled → bool
-
Same as enableInteractiveSelection.
no setter
- selectionHeightStyle → BoxHeightStyle
-
Controls how tall the selection highlight boxes are computed to be.
final
- selectionWidthStyle → BoxWidthStyle
-
Controls how wide the selection highlight boxes are computed to be.
final
- showCursor → bool
-
Whether to show cursor.
final
- showSelectionHandles → bool
-
Whether to show selection handles.
final
- smartDashesType → SmartDashesType
-
Whether to allow the platform to automatically format dashes.
final
- smartQuotesType → SmartQuotesType
-
Whether to allow the platform to automatically format quotes.
final
- spellCheckConfiguration → SpellCheckConfiguration?
-
Configuration that details how spell check should be performed.
final
- strutStyle → StrutStyle
-
The strut style used for the vertical layout.
no setter
- style → TextStyle
-
The text style to use for the editable text.
final
- textAlign → TextAlign
-
How the text should be aligned horizontally.
final
- textCapitalization → TextCapitalization
-
Configures how the platform keyboard will select an uppercase or
lowercase keyboard.
final
- textDirection → TextDirection?
-
The directionality of the text.
final
- textHeightBehavior → TextHeightBehavior?
-
Defines how to apply TextStyle.height over and under text.
final
- textInputAction → TextInputAction?
-
The type of action button to use with the soft keyboard.
final
- textScaleFactor → double?
-
Deprecated. Will be removed in a future version of Flutter. Use
textScaler instead.
final
- textScaler → TextScaler?
-
The font scaling strategy to use when laying out and rendering the text.
final
- textWidthBasis → TextWidthBasis
-
Defines how to measure the width of the rendered text.
final
- toolbarOptions → ToolbarOptions
-
Configuration of toolbar options.
final
- undoController → UndoHistoryController?
-
Controls the undo state of the current editable text.
final
Methods
-
createElement(
) → StatefulElement -
Creates a StatefulElement to manage this widget's location in the tree.
inherited
-
createState(
) → EditableTextState -
Creates the mutable state for this widget at a given location in the tree.
override
-
debugDescribeChildren(
) → List< DiagnosticsNode> -
Returns a list of DiagnosticsNode objects describing this node's
children.
inherited
-
debugFillProperties(
DiagnosticPropertiesBuilder properties) → void -
Add additional properties associated with the node.
override
-
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
toDiagnosticsNode(
{String? name, DiagnosticsTreeStyle? style}) → DiagnosticsNode -
Returns a debug representation of the object that is used by debugging
tools and by DiagnosticsNode.toStringDeep.
inherited
-
toString(
{DiagnosticLevel minLevel = DiagnosticLevel.info}) → String -
A string representation of this object.
inherited
-
toStringDeep(
{String prefixLineOne = '', String? prefixOtherLines, DiagnosticLevel minLevel = DiagnosticLevel.debug, int wrapWidth = 65}) → String -
Returns a string representation of this node and its descendants.
inherited
-
toStringShallow(
{String joiner = ', ', DiagnosticLevel minLevel = DiagnosticLevel.debug}) → String -
Returns a one-line detailed description of the object.
inherited
-
toStringShort(
) → String -
A short, textual description of this widget.
inherited
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited
Static Properties
- debugDeterministicCursor ↔ bool
-
Setting this property to true makes the cursor stop blinking or fading
on and off once the cursor appears on focus. This property is useful for
testing purposes.
getter/setter pair
Static Methods
-
getEditableButtonItems(
{required ClipboardStatus? clipboardStatus, required VoidCallback? onCopy, required VoidCallback? onCut, required VoidCallback? onPaste, required VoidCallback? onSelectAll, required VoidCallback? onLookUp, required VoidCallback? onSearchWeb, required VoidCallback? onLiveTextInput}) → List< ContextMenuButtonItem> - Returns the ContextMenuButtonItems representing the buttons in this platform's default selection menu for an editable field.