Validating Input
Check input and show helpful errors.
Validating Input is a free Android Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Android Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Why Validate Input
Users make mistakes: an empty name, a malformed email, a too-short password. Good forms catch these early and explain clearly what to fix.
In this lesson you'll add validation to Compose forms, show inline errors, and disable the submit button until everything is valid.
A Validation Rule is Just a Function
Keep validation logic as plain Kotlin functions that take a value and return whether it's valid (or an error message). This makes rules reusable and easy to test.
Here is a simple email check.
fun emailError(email: String): String? = when {
email.isBlank() -> "Email is required"
!email.contains("@") -> "Enter a valid email"
else -> null
}Showing the Error on the Field
OutlinedTextField has an isError flag and a supportingText slot. Combine them to show a red field with a message underneath.
The error comes straight from your validation function.
var email by remember { mutableStateOf("") }
val error = emailError(email)
OutlinedTextField(
value = email,
onValueChange = { email = it },
label = { Text("Email") },
isError = error != null,
supportingText = { if (error != null) Text(error) }
)Don't Yell Too Early
Showing "Email is required" before the user has even touched the field feels hostile. A common fix is to track whether a field has been touched and only show errors after.
Here we mark the field touched once it loses focus.
var email by remember { mutableStateOf("") }
var touched by remember { mutableStateOf(false) }
val error = if (touched) emailError(email) else null
OutlinedTextField(
value = email,
onValueChange = { email = it },
label = { Text("Email") },
isError = error != null,
modifier = Modifier.onFocusChanged {
if (!it.isFocused) touched = true
}
)Validating a Password
Passwords usually have several rules. Return the first failing rule so the user fixes one thing at a time.
Notice this is still a pure function with no UI inside.
fun passwordError(pw: String): String? = when {
pw.length < 8 -> "At least 8 characters"
pw.none { it.isDigit() } -> "Add a number"
pw.none { it.isUpperCase() } -> "Add an uppercase letter"
else -> null
}Cross-Field Validation
Some rules involve two fields, like "confirm password must match password". These can't live in a single-field function, so compute them where both values are available.
var password by remember { mutableStateOf("") }
var confirm by remember { mutableStateOf("") }
val confirmError =
if (confirm.isNotEmpty() && confirm != password)
"Passwords don't match"
else nullDisabling Submit Until Valid
The whole form is valid when every rule passes. Compute a single boolean and use it to enable or disable the submit button.
This prevents the user from submitting bad data in the first place.
val formValid =
emailError(email) == null &&
passwordError(password) == null &&
confirmError == null
Button(onClick = { submit() }, enabled = formValid) {
Text("Create Account")
}Validating on Submit
Inline validation guides the user, but you should also re-check everything when they press submit. The submit handler decides whether to proceed or surface all errors at once.
fun onSubmit() {
val errors = listOfNotNull(
emailError(email),
passwordError(password)
)
if (errors.isEmpty()) {
register(email, password)
} else {
// show errors / mark fields touched
}
}Restricting What Can Be Typed
Validation can also be preventive. For a phone number, simply ignore non-digit characters inside onValueChange so the bad input never enters state.
This is friendlier than scolding the user afterward.
var phone by remember { mutableStateOf("") }
OutlinedTextField(
value = phone,
onValueChange = { input ->
phone = input.filter { it.isDigit() }.take(10)
},
label = { Text("Phone") }
)Centralizing Validation in the ViewModel
For real screens, keep validation in the ViewModel so the UI just displays results. The ViewModel exposes errors and a isValid flag.
This keeps composables dumb and your rules unit-testable.
class SignUpViewModel : ViewModel() {
var email by mutableStateOf("")
private set
val emailError: String?
get() = emailError(email)
val isValid: Boolean
get() = emailError == null && email.isNotBlank()
fun onEmailChange(value: String) { email = value }
}Pure Kotlin: Testing the Rules
Because validators are pure functions, you can run them anywhere. Here the email and password rules execute standalone, just like a unit test would call them.
fun emailError(email: String): String? = when {
email.isBlank() -> "Email is required"
!email.contains("@") -> "Enter a valid email"
else -> null
}
fun main() {
println(emailError(""))
println(emailError("nope"))
println(emailError("ada@dev.io"))
}Quick Check
Which property pair on OutlinedTextField is used to mark a field invalid and show a message under it?
Recap
You now validate Compose forms cleanly:
- Keep rules as pure functions returning an error message or null.
- Show errors with
isError+supportingText, and avoid yelling before a field is touched. - Handle cross-field rules where both values are visible.
- Disable submit until the whole form is valid, and re-check on submit.
- Prevent bad input with
filter, and centralize rules in a ViewModel.
Next: keyboard types, IME actions and focus management.
Frequently asked questions
Is the “Validating Input” lesson free?
Yes — the full text of “Validating Input” is free to read here on the web, and the Android Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Android Academy course, upgrade to CoddyKit PRO.
What will I learn in “Validating Input”?
Check input and show helpful errors. You practise Android Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Android Academy?
No prior experience is required. Android Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Validating Input” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Android Academy lesson?
Yes. Every Android Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.