Jetpack Compose TextField — Complete Guide
In this tutorial, you'll learn about Jetpack Compose TextField. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
The Problem
Your TextField doesn't validate input, the keyboard doesn't dismiss on action, or the visual transformation for passwords shows characters briefly.
Wrong Approach ❌
@Composable
fun BadTextField() {
var text by remember { mutableStateOf("") }
OutlinedTextField(
value = text,
onValueChange = { text = it }, // No input filtering
label = { Text("Age") },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number)
)
// User can type letters into a number field!
}
Output: Invalid input accepted. Keyboard doesn't respond to IME actions.
Right Approach ✅
@Composable
fun GoodTextField() {
var text by remember { mutableStateOf("") }
var hasError by remember { mutableStateOf(false) }
OutlinedTextField(
value = text,
onValueChange = { input ->
// Filter input — only allow digits
val filtered = input.filter { it.isDigit() }
if (filtered != input) hasError = true
text = filtered
},
label = { Text("Age") },
isError = hasError,
supportingText = {
if (hasError) Text("Only numbers are allowed", color = MaterialTheme.colorScheme.error)
},
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number,
imeAction = ImeAction.Done
),
keyboardActions = KeyboardActions(
onDone = { /* dismiss keyboard, submit form */ }
),
visualTransformation = VisualTransformation.None,
singleLine = true
)
}
// Password field
@Composable
fun PasswordField() {
var password by remember { mutableStateOf("") }
var visible by remember { mutableStateOf(false) }
OutlinedTextField(
value = password,
onValueChange = { password = it },
label = { Text("Password") },
visualTransformation = if (visible) VisualTransformation.None else PasswordVisualTransformation(),
trailingIcon = {
IconButton(onClick = { visible = !visible }) {
Icon(if (visible) Icons.Default.VisibilityOff else Icons.Default.Visibility, "")
}
}
)
}
Output: Proper input validation, keyboard handling, and password masking.
Prevention
- Always filter input in
onValueChangefor constrained fields. - Configure
KeyboardOptionswith correctkeyboardTypeandimeAction. - Use
isError+supportingTextfor inline validation. - Use
PasswordVisualTransformationfor secure password entry.
Common Mistakes with compose text field
- Using
headandtailinstead of pattern matching, causing runtime errors on empty lists - Forgetting that lazy evaluation defers computation until the value is forced, causing space leaks with unevaluated thunks
- Using
returnto exit a function early instead of wrapping a pure value in the monad
These mistakes appear frequently in real-world Android code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.
Practice Exercise
Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.
This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro