TextFieldState


The editable text state of a text field, including both the text itself and position of the cursor or selection.

To change the text field contents programmatically, call edit, setTextAndSelectAll, setTextAndPlaceCursorAtEnd, or clearText. Individual parts of the state like text, selection, or composition can be read from any snapshot restart scope like Composable functions. To observe these members from outside a restart scope, use snapshotFlow { textFieldState.text } or snapshotFlow { textFieldState.selection }.

When instantiating this class from a composable, use rememberTextFieldState to automatically save and restore the field state. For more advanced use cases, pass TextFieldState.Saver to rememberSaveable.

import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.input.TextFieldState import androidx.compose.foundation.text.input.setTextAndPlaceCursorAtEnd import androidx.compose.material.Icon import androidx.compose.material.IconButton import androidx.compose.material.Text import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Clear import androidx.compose.runtime.Composable import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.TextStyle import androidx.compose.ui.unit.sp class SearchViewModel(val searchFieldState: TextFieldState = TextFieldState()) {  private val queryValidationRegex = """\w+""".toRegex()  // Use derived state to avoid recomposing every time the text changes, and only recompose  // when the input becomes valid or invalid.  val isQueryValid by derivedStateOf {  // This lambda will be re-executed every time inputState.text changes.  searchFieldState.text.matches(queryValidationRegex)  }  var searchResults: List<String> by mutableStateOf(emptyList())  private set  /** Called while the view model is active, e.g. from a LaunchedEffect. */  suspend fun run() {  snapshotFlow { searchFieldState.text }  .collectLatest { queryText ->  // Start a new search every time the user types something valid. If the previous  // search is still being processed when the text is changed, it will be  // cancelled  // and this code will run again with the latest query text.  if (isQueryValid) {  searchResults = performSearch(query = queryText)  }  }  }  fun clearQuery() {  searchFieldState.setTextAndPlaceCursorAtEnd("")  }  private suspend fun performSearch(query: CharSequence): List<String> {  TODO()  } } @Composable fun SearchScreen(viewModel: SearchViewModel) {  Column {  Row {  BasicTextField(viewModel.searchFieldState)  IconButton(onClick = { viewModel.clearQuery() }) {  Icon(Icons.Default.Clear, contentDescription = "clear search query")  }  }  if (!viewModel.isQueryValid) {  Text("Invalid query", style = TextStyle(color = Color.Red))  }  LazyColumn { items(viewModel.searchResults) { TODO() } }  } }

Summary

Nested types

Saves and restores a TextFieldState for rememberSaveable.

Public constructors

@RememberInComposition
TextFieldState(initialText: String, initialSelection: TextRange)
Cmn

Public functions

inline Unit
edit(block: TextFieldBuffer.() -> Unit)

Runs block with a mutable version of the current state.

Cmn
open String
Cmn

Public properties

TextRange?

The current composing range dictated by the IME.

Cmn
TextRange

The current selection range.

Cmn
CharSequence

The current text content.

Cmn
UndoState

Undo history controller for this TextFieldState.

Cmn

Extension functions

Unit

Deletes all the text in the state.

Cmn
Unit

Sets the text in this TextFieldState to text, replacing any text that was previously there, and places the cursor at the end of the new text.

Cmn
Unit

Sets the text in this TextFieldState to text, replacing any text that was previously there, and selects all the text.

Cmn
TextFieldBuffer

Creates a temporary, mutable TextFieldBuffer representing the current state of this TextFieldState.

Cmn

Public constructors

TextFieldState

@RememberInComposition
TextFieldState(
    initialText: String = "",
    initialSelection: TextRange = TextRange(initialText.length)
)

Public functions

edit

inline fun edit(block: TextFieldBuffer.() -> Unit): Unit

Runs block with a mutable version of the current state. The block can make changes to the text and cursor/selection. See the documentation on TextFieldBuffer for a more detailed description of the available operations.

Make sure that you do not make concurrent calls to this function or call it again inside block's scope. Doing either of these actions will result in triggering an IllegalStateException.

import androidx.compose.foundation.text.input.TextFieldState import androidx.compose.foundation.text.input.delete import androidx.compose.foundation.text.input.insert import androidx.compose.material.Text import androidx.compose.ui.text.TextRange val state = TextFieldState("hello world!") state.edit {  // Insert a comma after "hello".  insert(5, ",") // = "hello, world!"  // Delete the exclamation mark.  delete(12, 13) // = "hello, world"  // Add a different name.  append("Compose") // = "hello, Compose"  // Say goodbye.  replace(0, 5, "goodbye") // "goodbye, Compose"  // Select the new name so the user can change it by just starting to type.  selection = TextRange(9, 16) // "goodbye, ̲C̲o̲m̲p̲o̲s̲e" }

toString

open fun toString(): String

Public properties

composition

val compositionTextRange?

The current composing range dictated by the IME. If null, there is no composing region.

To observe changes to this property outside a restartable function, use snapshotFlow { composition }.

selection

val selectionTextRange

The current selection range. If the selection is collapsed, it represents cursor location. This value will automatically update when the user enters text or otherwise changes the text field selection range. To change it programmatically, call edit.

To observe changes to this property outside a restartable function, use snapshotFlow { selection }.

text

val textCharSequence

The current text content. This value will automatically update when the user enters text or otherwise changes the text field contents. To change it programmatically, call edit.

To observe changes to this property outside a restartable function, use snapshotFlow { text }.

import androidx.compose.foundation.layout.Column import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.input.TextFieldState import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.unit.sp class SearchViewModel {  val searchFieldState = TextFieldState()  var searchResults: List<String> by mutableStateOf(emptyList())  private set  /** Called while the view model is active, e.g. from a LaunchedEffect. */  suspend fun run() {  snapshotFlow { searchFieldState.text }  // Let fast typers get multiple keystrokes in before kicking off a search.  .debounce(500)  // collectLatest cancels the previous search if it's still running when there's a  // new change.  .collectLatest { queryText -> searchResults = performSearch(query = queryText) }  }  private suspend fun performSearch(query: CharSequence): List<String> {  TODO()  } } @Composable fun SearchScreen(viewModel: SearchViewModel) {  Column {  BasicTextField(viewModel.searchFieldState)  LazyColumn { items(viewModel.searchResults) { TODO() } }  } }
See also
edit
snapshotFlow

undoState

@ExperimentalFoundationApi
val undoStateUndoState

Undo history controller for this TextFieldState.

import androidx.compose.foundation.border import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.input.TextFieldState import androidx.compose.foundation.text.input.rememberTextFieldState import androidx.compose.material.Text import androidx.compose.material.icons.filled.Clear import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.TextStyle import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp val state = rememberTextFieldState() Column(Modifier.padding(8.dp)) {  Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {  androidx.compose.material.Button(  onClick = { state.undoState.undo() },  enabled = state.undoState.canUndo,  ) {  Text("Undo")  }  androidx.compose.material.Button(  onClick = { state.undoState.redo() },  enabled = state.undoState.canRedo,  ) {  Text("Redo")  }  androidx.compose.material.Button(  onClick = { state.undoState.clearHistory() },  enabled = state.undoState.canUndo || state.undoState.canRedo,  ) {  Text("Clear History")  }  }  BasicTextField(  state = state,  modifier =  Modifier.fillMaxWidth()  .border(1.dp, Color.LightGray, RoundedCornerShape(6.dp))  .padding(8.dp),  textStyle = TextStyle(fontSize = 16.sp),  ) }

Extension functions

fun TextFieldState.clearText(): Unit

Deletes all the text in the state.

To perform more complicated edits on the text, call TextFieldState.edit. This function is equivalent to calling:

edit {
delete(0, length)
placeCursorAtEnd()
}

setTextAndPlaceCursorAtEnd

fun TextFieldState.setTextAndPlaceCursorAtEnd(text: String): Unit

Sets the text in this TextFieldState to text, replacing any text that was previously there, and places the cursor at the end of the new text.

To perform more complicated edits on the text, call TextFieldState.edit. This function is equivalent to calling:

edit {
replace(0, length, text)
placeCursorAtEnd()
}

setTextAndSelectAll

fun TextFieldState.setTextAndSelectAll(text: String): Unit

Sets the text in this TextFieldState to text, replacing any text that was previously there, and selects all the text.

To perform more complicated edits on the text, call TextFieldState.edit. This function is equivalent to calling:

edit {
replace(0, length, text)
selectAll()
}

toTextFieldBuffer

fun TextFieldState.toTextFieldBuffer(): TextFieldBuffer

Creates a temporary, mutable TextFieldBuffer representing the current state of this TextFieldState.

Use a TextFieldBuffer to:

  • Apply transformations for testing purposes

  • Preview how the TextField would render with a specific OutputTransformation

This is similar to calling TextFieldState.edit, but without committing the changes back to the TextFieldState.

Important: A TextFieldBuffer is intended for short-term use. Let the garbage collector dispose of it when you're finished to avoid unnecessary memory usage.

import androidx.compose.foundation.text.input.OutputTransformation import androidx.compose.foundation.text.input.TextFieldBuffer import androidx.compose.foundation.text.input.TextFieldState import androidx.compose.foundation.text.input.insert import androidx.compose.foundation.text.input.toTextFieldBuffer import androidx.compose.material.Text val state = TextFieldState("Hello, World") val outputTransformation = OutputTransformation { insert(0, "> ") } val buffer = state.toTextFieldBuffer() with(outputTransformation) { buffer.transformOutput() } val transformedText = buffer.asCharSequence() val transformedSelection = buffer.selection