Quick take: EditText reads single or multi-line text input from the user. Set inputType, hint, and maxLength in XML, then read editText.text.toString() in Kotlin to get the value. Toast.makeText(context, message, duration).show() is the simplest way to confirm a submission. For Material 3 apps, prefer TextInputEditText inside a TextInputLayout for floating labels and error states.
EditText is one of the oldest widgets in the Android framework, and it shows. The API is a little quirky (the text property returns an Editable, not a String), the validation patterns are mostly self-rolled, and Material Components add a wrapper layer on top to make it look modern. But it works on every Android version since the platform began, and every form, every login screen, every search box uses it.
I'll walk through the XML attributes that matter, the Kotlin code to read and validate input, and how to give feedback with a Toast. Along the way, a few lifecycle pitfalls that catch new devs.
How Do You Add an EditText in XML?
The minimum viable EditText looks like this:
<EditText
android:id="@+id/name_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Your name"
android:inputType="textPersonName"
android:maxLength="50" />
Four attributes matter:
android:idis required for view binding to give you a typed referenceandroid:hintshows placeholder text when the field is emptyandroid:inputTypetells the keyboard what kind of input to expect (and sets autocorrect rules)android:maxLengthcaps how many characters the user can type
Common inputType values worth knowing:
| inputType | Keyboard | Notes |
|---|---|---|
| text | Default | Plain text with autocorrect |
| textPersonName | Default, no autocorrect | Names |
| textEmailAddress | Adds @ and . on the keyboard | |
| textPassword | Hides input as dots | Password |
| textMultiLine | Adds Enter key for new lines | Long text |
| number | Numeric keypad | Whole numbers |
| numberDecimal | Numeric with . | Decimals |
| phone | Phone keypad | Phone numbers |
Pick the right one. Showing the wrong keyboard for the wrong field is a surprisingly common accessibility issue, especially on tablets where the user can't always switch easily.
Material 3 Approach
For Material 3 apps, wrap the EditText in a TextInputLayout and use TextInputEditText:
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/name_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Your name"
style="@style/Widget.Material3.TextInputLayout.OutlinedBox">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/name_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPersonName"
android:maxLength="50" />
</com.google.android.material.textfield.TextInputLayout>
This gives you a floating label, a built-in error display, and the outlined box style every modern Android app uses. The hint moves up to the top of the box on focus, which is the Material spec behaviour.
How Do You Read EditText Input in Kotlin?
Assuming view binding is enabled, reading the value is one line:
val name: String = binding.nameInput.text.toString()
The .text property returns an Editable, which is essentially a mutable string. Converting to String with .toString() gives you a stable, immutable value to work with. Add .trim() to drop accidental leading/trailing whitespace, which copy-paste often introduces:
val name: String = binding.nameInput.text.toString().trim()
That one line covers about 95% of cases. The remaining 5% involves real-time validation as the user types, which uses a TextWatcher:
binding.nameInput.doAfterTextChanged { editable ->
val current = editable.toString()
binding.submitButton.isEnabled = current.length >= 3
}
doAfterTextChanged is a Kotlin extension on EditText that wraps the older TextWatcher interface. Per the Android KTX docs, it's the recommended approach for new Kotlin code. The lambda fires after each character change, so you can enable or disable the submit button based on current input.
How Do You Validate Input Before Showing a Toast?
Pair a button with the EditText, validate inside the click handler, and show different Toast messages for success and failure:
binding.submitButton.setOnClickListener {
val name = binding.nameInput.text.toString().trim()
when {
name.isEmpty() -> {
Toast.makeText(this, "Please enter a name", Toast.LENGTH_SHORT).show()
}
name.length < 2 -> {
Toast.makeText(this, "Name must be at least 2 characters", Toast.LENGTH_SHORT).show()
}
else -> {
Toast.makeText(this, "Hello, $name", Toast.LENGTH_LONG).show()
binding.nameInput.text?.clear()
}
}
}
A few things worth noting:
name.isEmpty()is the Kotlin equivalent ofname.length == 0, but more readable- The
whenblock reads top-to-bottom, the first matching branch wins binding.nameInput.text?.clear()empties the field after success, the?is becausetextis technically nullable
For Material 3 with TextInputLayout, you can attach the error to the field itself instead of using Toast:
if (name.isEmpty()) {
binding.nameLayout.error = "Please enter a name"
} else {
binding.nameLayout.error = null
Toast.makeText(this, "Hello, $name", Toast.LENGTH_LONG).show()
}
}
The error appears in red below the field, the box outline turns red, and the floating label switches colour. Much better UX than a Toast for validation errors, save Toasts for confirmations and transient feedback.
## How Do You Show a Toast?
Three parameters, then `.show()`:
```kotlin
Toast.makeText(context, message, duration).show()
contextisthisin an activity orrequireContext()in a fragmentmessageis a String or a string resource IDdurationisToast.LENGTH_SHORT(about 2 seconds) orToast.LENGTH_LONG(about 3.5 seconds)
Calling .makeText without .show() is the most common Toast mistake. The code compiles, runs, and silently does nothing. I've seen this in production code at three different jobs.
A few more Toast facts that come up:
- Two Toasts in a row get queued, the second appears after the first fades out
- You can hold a reference to a Toast and call
.cancel()to dismiss early - On Android 11+, the position is fixed near the bottom,
setGravityis ignored for non-system apps for accessibility reasons
If you need more than Toast offers (custom layouts, actions, custom durations), use Snackbar from Material Components instead.
What About the Activity Lifecycle?
EditText state survives rotation automatically, as long as you set android:id. The framework calls onSaveInstanceState before destroying the activity and restores the text in the recreated activity's onCreate. You don't write any code for this.
What doesn't survive automatically:
- Custom data you derived from the input (parsed numbers, validation state)
- Cursor position if you're doing tricky text manipulation
- Focus, if you've focus-shifted programmatically
For custom state, override onSaveInstanceState and onRestoreInstanceState:
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putBoolean("submitted", hasSubmitted)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
hasSubmitted = savedInstanceState?.getBoolean("submitted") ?: false
}
In practice, I push this kind of state into a ViewModel and let the EditText handle its own text restoration. Less ceremony, better separation. A ViewModel is the right tool for state that needs to survive rotation but doesn't belong in the view itself.
What Are the Common Pitfalls?
A short list from real projects:
- Wrong inputType. A phone number field with default text input is a usability disaster on every device. Always pick the right one.
- Forgetting
.trim(). Pasted email addresses bring leading or trailing spaces. Validation fails for non-obvious reasons. - Reading the value too early. If you read
binding.nameInput.text.toString()inonCreatebefore the user types anything, you get an empty string. Read it in the click handler. - Skipping accessibility. Set
android:contentDescriptionor use the floating label so screen readers announce the field properly. Honestly, this is the one most developers (me included) forget on first pass.
Get those four right and EditText becomes a non-issue. The harder work is what you do with the input after, which usually means a ViewModel, a repository, and eventually a network call. That's a whole different post.
Related
- Android Kotlin Introduction - the language basics behind these snippets
- Button OnClick in Android Kotlin - the Button half of a form
- Android Introduction - lifecycle and project structure context
- ImageView in Android Kotlin - the other widget you'll add to most screens