Android
Keyboard Customization
Search Button
Android Development
User Interface

Android how to make keyboard enter button say Search and handle its click?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

On Android, the keyboard action button can be changed from a generic enter key to a search action, which makes search forms feel much more deliberate. The complete solution has two parts: request the search action in the input field and handle the IME action reliably when the user presses it.

Request the Search Action in XML

For a classic EditText, the first step is to ask the input method editor for a search action:

xml
1<EditText
2    android:id="@+id/searchInput"
3    android:layout_width="match_parent"
4    android:layout_height="wrap_content"
5    android:hint="Search"
6    android:inputType="text"
7    android:imeOptions="actionSearch" />

This does not guarantee every keyboard will draw the exact same icon or label, but it tells the IME that the field semantically represents search input.

That distinction matters. Android keyboards are allowed to render the action in slightly different ways, but the intent stays consistent.

Handle the Action in Code

Setting imeOptions changes the UI request. It does not automatically perform the search. You still need a listener.

kotlin
1import android.os.Bundle
2import android.view.KeyEvent
3import android.view.inputmethod.EditorInfo
4import android.widget.EditText
5import androidx.appcompat.app.AppCompatActivity
6
7class SearchActivity : AppCompatActivity() {
8
9    override fun onCreate(savedInstanceState: Bundle?) {
10        super.onCreate(savedInstanceState)
11        setContentView(R.layout.activity_search)
12
13        val searchInput = findViewById<EditText>(R.id.searchInput)
14
15        searchInput.setOnEditorActionListener { _, actionId, event ->
16            val isSearchAction = actionId == EditorInfo.IME_ACTION_SEARCH
17            val isEnterFallback =
18                event?.keyCode == KeyEvent.KEYCODE_ENTER &&
19                event.action == KeyEvent.ACTION_DOWN
20
21            if (isSearchAction || isEnterFallback) {
22                submitSearch(searchInput.text.toString())
23                true
24            } else {
25                false
26            }
27        }
28    }
29
30    private fun submitSearch(raw: String) {
31        val query = raw.trim()
32        if (query.isNotEmpty()) {
33            println("Searching for $query")
34        }
35    }
36}

The fallback enter-key check matters because some keyboards and hardware devices do not send exactly the same callback pattern.

Why Returning true Matters

If you handled the action, return true. That tells Android the event has been consumed.

If you return false after performing the search, the event can continue through fallback handling and sometimes cause duplicate behavior. That often shows up as:

  • duplicate search requests
  • unexpected new lines
  • inconsistent behavior across keyboard apps

So the listener is not only about catching the search action. It is also about consuming it correctly.

Hide the Keyboard After Submission

Search screens usually feel better if the keyboard closes after a valid query is submitted.

kotlin
1import android.content.Context
2import android.view.View
3import android.view.inputmethod.InputMethodManager
4
5fun hideKeyboard(view: View) {
6    val imm = view.context.getSystemService(
7        Context.INPUT_METHOD_SERVICE
8    ) as InputMethodManager
9
10    imm.hideSoftInputFromWindow(view.windowToken, 0)
11}

You can call this inside submitSearch after validation and before showing results.

That is optional, but it often improves the perceived flow on search-heavy screens.

Jetpack Compose Version

If the screen is written in Compose, the equivalent setup uses KeyboardOptions and KeyboardActions.

kotlin
1import androidx.compose.foundation.text.KeyboardActions
2import androidx.compose.foundation.text.KeyboardOptions
3import androidx.compose.material3.TextField
4import androidx.compose.runtime.*
5import androidx.compose.ui.text.input.ImeAction
6
7@Composable
8fun SearchBox(onSearch: (String) -> Unit) {
9    var query by remember { mutableStateOf("") }
10
11    TextField(
12        value = query,
13        onValueChange = { query = it },
14        keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search),
15        keyboardActions = KeyboardActions(
16            onSearch = {
17                val trimmed = query.trim()
18                if (trimmed.isNotEmpty()) {
19                    onSearch(trimmed)
20                }
21            }
22        )
23    )
24}

The concepts are the same. You request a search action and connect that action to one shared submit function.

Keep the Search Logic Centralized

Whether you use XML views or Compose, the submit path should be centralized. A visible search button, the keyboard action, and any retry action should all call the same function.

That helps keep validation consistent:

  • trim whitespace once
  • reject empty queries once
  • trigger analytics once
  • start the actual search request once

Scattering the logic across different listeners usually creates subtle inconsistencies.

Common Pitfalls

The most common pitfall is setting android:imeOptions="actionSearch" and assuming that alone handles the click. It only requests the keyboard UI.

Another mistake is listening only for the IME action and ignoring hardware-enter fallbacks. External keyboards and some IMEs can behave differently.

A third issue is returning false after a successful search, which may let the event propagate and trigger duplicate handling.

Finally, many implementations submit empty strings because they do not trim or validate the query before dispatching the search.

Summary

  • Use android:imeOptions="actionSearch" to request a search action from the keyboard.
  • Handle the action with setOnEditorActionListener for views or KeyboardActions in Compose.
  • Support enter-key fallback for broader keyboard compatibility.
  • Return true after handling the action to avoid duplicate behavior.
  • Route all search triggers through one shared submit function with proper validation.

Course illustration
Course illustration

All Rights Reserved.