hide keyboard jetpack compose

How to Hide the Keyboard in Jetpack Compose: Tutorial

hide keyboard jetpack compose

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:

  • Why controlling the keyboard is important
  • The main APIs for hiding the keyboard in Compose
  • Step-by-step code examples
  • Handling keyboard dismissal in different scenarios
  • Best practices and common pitfalls

Why Do You Need to Hide the Keyboard in Jetpack Compose?

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:

  • The user presses a Submit or Done button
  • The user navigates to a new screen where typing is not needed
  • The user taps outside of the input field
  • You want to clear focus programmatically after data entry
  • You need to ensure a button or form at the bottom of the screen is not hidden behind the keyboard

Not handling the keyboard properly often leads to bad reviews because users find it frustrating when UI elements are blocked.

Methods to Hide the Keyboard in Jetpack Compose

There are three main approaches:

  1. Using LocalSoftwareKeyboardController
  2. Clearing focus with LocalFocusManager
  3. Dismissing keyboard on outside taps or navigation events

1. Hiding Keyboard with 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.

2. Hiding Keyboard by Clearing Focus

@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.

3. Hiding Keyboard on Outside Tap

@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.

Advanced: Hiding Keyboard on Navigation

@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.

Common Pitfalls

  • Relying only on keyboardController.hide() – it may not work consistently on all devices
  • Forgetting accessibility – always provide clear submission actions
  • Not testing on multiple devices – OEM keyboards sometimes behave differently

Best Practices

  • Prefer focusManager.clearFocus() for reliability
  • Combine multiple approaches (Done button, outside taps, navigation)
  • Always test on real devices and emulators
  • Handle KeyboardActions for better UX

Conclusion

Hiding 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.

FAQ

How do I hide the keyboard when pressing Done in Jetpack Compose?

Use KeyboardActions(onDone = { focusManager.clearFocus() }) inside your TextField.

How do I hide the keyboard when tapping outside a TextField?

Wrap your layout in a Modifier.clickable or Modifier.pointerInput and call focusManager.clearFocus().

Should I use InputMethodManager in Jetpack Compose?

No, Compose provides its own APIs. Use LocalSoftwareKeyboardController or LocalFocusManager instead.

Is LocalSoftwareKeyboardController reliable?

Yes, but for the best results combine it with focusManager.clearFocus() to cover all cases.

Do I need Kotlin to use these APIs?

Yes. Jetpack Compose is built for Kotlin, so these APIs are only available in Kotlin.