Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
When building Android apps with Jetpack Compose, one of the first problems developers run into is how to hide the software keyboard at the right time. If the keyboard stays open after the user finishes typing, it can block important UI elements, overlap buttons, and create a clunky user experience.
If you have been working with the classic XML and EditText
world, you might remember handling the keyboard with InputMethodManager
. In Jetpack Compose, things are a bit different but also much cleaner once you know the right APIs.
In this article, we’ll cover:
The keyboard in Android usually opens automatically when a text field receives focus. That’s great for usability, but developers need to dismiss it when:
Not handling the keyboard properly often leads to bad reviews because users find it frustrating when UI elements are blocked.
There are three main approaches:
LocalSoftwareKeyboardController
LocalFocusManager
LocalSoftwareKeyboardController
@Composable
fun HideKeyboardWithController() {
var text by remember { mutableStateOf(TextFieldValue("")) }
val keyboardController = LocalSoftwareKeyboardController.current
Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
OutlinedTextField(
value = text,
onValueChange = { text = it },
label = { Text("Type something") },
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(16.dp))
Button(onClick = { keyboardController?.hide() }, modifier = Modifier.fillMaxWidth()) {
Text("Submit")
}
}
}
This explicitly hides the keyboard when the Submit button is clicked.
@Composable
fun HideKeyboardByClearingFocus() {
var text by remember { mutableStateOf("") }
val focusManager = LocalFocusManager.current
OutlinedTextField(
value = text,
onValueChange = { text = it },
label = { Text("Enter text") },
modifier = Modifier.fillMaxWidth(),
keyboardActions = KeyboardActions(
onDone = { focusManager.clearFocus() }
)
)
}
Here, pressing Done on the keyboard automatically dismisses it.
@Composable
fun HideKeyboardOnOutsideTap() {
var text by remember { mutableStateOf("") }
val focusManager = LocalFocusManager.current
Box(
modifier = Modifier
.fillMaxSize()
.background(Color.White)
.clickable { focusManager.clearFocus() }
.padding(16.dp)
) {
OutlinedTextField(
value = text,
onValueChange = { text = it },
label = { Text("Tap outside to hide keyboard") },
modifier = Modifier.fillMaxWidth()
)
}
}
This is useful when users expect the keyboard to close by tapping outside the input field.
@Composable
fun NavigationExample(navController: NavController = rememberNavController()) {
val focusManager = LocalFocusManager.current
Button(onClick = {
focusManager.clearFocus()
navController.navigate("nextScreen")
}) {
Text("Go to Next Screen")
}
}
Always clear focus before navigating so the keyboard doesn’t remain open on the next screen.
keyboardController.hide()
– it may not work consistently on all devicesfocusManager.clearFocus()
for reliabilityKeyboardActions
for better UXHiding the keyboard in Jetpack Compose is easier than it looks. Use LocalSoftwareKeyboardController
for explicit control and LocalFocusManager
for more natural dismissal through focus changes. By combining both approaches, your app will feel polished and professional, giving users a smoother experience.
Use KeyboardActions(onDone = { focusManager.clearFocus() })
inside your TextField
.
Wrap your layout in a Modifier.clickable
or Modifier.pointerInput
and call focusManager.clearFocus()
.
No, Compose provides its own APIs. Use LocalSoftwareKeyboardController
or LocalFocusManager
instead.
Yes, but for the best results combine it with focusManager.clearFocus()
to cover all cases.
Yes. Jetpack Compose is built for Kotlin, so these APIs are only available in Kotlin.