
In this article, we’ll learn how to implement the Search Bar in Material 3 Jetpack Compose.
Prerequisites:
What is a Search Bar?
Search Bar lets people enter a keyword or phrase to get relevant information.
Example:

Let’s implement it in the Android Studio.
First, create an empty Compose project and add the following dependency in the app level gradle file:
// this is the material icon dependency
// its size is large, so enable proguard in the production
implementation "androidx.compose.material:material-icons-extended"
Next, open MainActivity. Create a Composable called MyUI() and call it from the onCreate(). We’ll write our code in it.
import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.History
import androidx.compose.material.icons.filled.Search
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SearchBar
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
YourProjectNameTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally
) {
MyUI()
}
}
}
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MyUI() {
}
Jetpack Compose provides SearchBar() method. It was added in the version 1.1.0.
@ExperimentalMaterial3Api
@Composable
fun SearchBar(
query: String,
onQueryChange: (String) -> Unit,
onSearch: (String) -> Unit,
active: Boolean,
onActiveChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
placeholder: @Composable (() -> Unit)? = null,
leadingIcon: @Composable (() -> Unit)? = null,
trailingIcon: @Composable (() -> Unit)? = null,
shape: Shape = SearchBarDefaults.inputFieldShape,
colors: SearchBarColors = SearchBarDefaults.colors(),
tonalElevation: Dp = SearchBarDefaults.TonalElevation,
shadowElevation: Dp = SearchBarDefaults.ShadowElevation,
windowInsets: WindowInsets = SearchBarDefaults.windowInsets,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable ColumnScope.() -> Unit,
)
query – It is the text that users enter in the search bar’s input field.
onQueryChange – It is a lambda that gets called every time the user updates the text in the input field. It provides the new (updated) query.
onSearch – It is triggered when the user taps on the Search icon on the keyboard. The current query comes as a parameter of this callback.
active – Whether this search bar is active.
onActiveChange – It is called when this search bar’s active state is changed.
modifier – The Modifier to be applied to this search bar.
enabled – It controls the enabled state of this search bar. When false, this component will not respond to user input, and it will appear visually disabled and disabled to accessibility services.
placeholder – An optional text to be displayed when the search bar’s query is empty.
leadingIcon – The icon to be displayed at the beginning of the search bar container.
trailingIcon – The icon to be displayed at the end of the search bar container.
shape – The shape of this search bar when it is not active. When active, the shape will always be SearchBarDefaults.fullScreenShape.
colors – The colors of the search bar.
tonalElevation – The toanl elevation.
shadowElevation – The shadow below the search bar.
windowInsets – The window insets that the search bar will respect.
interactionSource – It helps us to observe and customize the interactions. For example, we can disable the ripple effect.
content – The content of this search bar when it is active. Here, we can display suggestions or search history data.
Let’s add it in the MyUI().
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MyUI() {
// this is the text users enter
var queryString by remember {
mutableStateOf("")
}
// if the search bar is active or not
var isActive by remember {
mutableStateOf(false)
}
val contextForToast = LocalContext.current.applicationContext
SearchBar(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = if (isActive) 0.dp else 8.dp),
query = queryString,
onQueryChange = { newQueryString ->
queryString = newQueryString
},
onSearch = {
isActive = false
Toast.makeText(contextForToast, "Your query string: $queryString", Toast.LENGTH_SHORT)
.show()
},
active = isActive,
onActiveChange = { activeChange ->
isActive = activeChange
},
placeholder = {
Text(text = "Search")
},
leadingIcon = {
Icon(imageVector = Icons.Default.Search, contentDescription = null)
}
) {
}
}
Output:

We created two variables – queryString and isActive.
queryString represents the text users enter in the search bar. It is similar to the value parameter of the TextField().
isActive indicates if the search bar is active or not.
The onQueryChange gets triggered every time the user enters a new character. It is similar to the onValueChange of the TextField().
The onSearch gets triggered when the user taps on the Search icon on the keyboard.
Let’s display the search history while the user enters the data.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MyUI() {
var historyItems = remember {
mutableStateListOf("SemicolonSpace", "Jetpack Compose", "Android")
}
SearchBar(
onSearch = {
isActive = false
Toast.makeText(contextForToast, "Your query string: $queryString", Toast.LENGTH_SHORT)
.show()
historyItems.add(queryString) // add the search term to the list
}
) {
// this is a column scope
historyItems.forEach { historyItem ->
Row(modifier = Modifier.padding(all = 16.dp)) {
Icon(
modifier = Modifier.padding(end = 12.dp),
imageVector = Icons.Default.History, contentDescription = null
)
Text(text = historyItem)
}
}
}
}
Output:

We created a historyItems variable to store the previous search items. In the content block, we added these items using the forEach() method. The content is a column scope. So, all the items are displayed vertically.
Here is the complete code:
import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.History
import androidx.compose.material.icons.filled.Search
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SearchBar
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
YourProjectNameTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally
) {
MyUI()
}
}
}
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MyUI() {
// this is the text users enter
var queryString by remember {
mutableStateOf("")
}
// if the search bar is active or not
var isActive by remember {
mutableStateOf(false)
}
val contextForToast = LocalContext.current.applicationContext
// previous search terms
var historyItems = remember {
mutableStateListOf("SemicolonSpace", "Jetpack Compose", "Android")
}
SearchBar(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = if (isActive) 0.dp else 8.dp),
query = queryString,
onQueryChange = { newQueryString ->
// this is called every time the user enters a new character
queryString = newQueryString
},
onSearch = {
// this is called when the user taps on the Search icon on the keyboard
isActive = false
Toast.makeText(contextForToast, "Your query string: $queryString", Toast.LENGTH_SHORT)
.show()
historyItems.add(queryString) // add the current search term to the list
},
active = isActive,
onActiveChange = { activeChange ->
isActive = activeChange
},
placeholder = {
Text(text = "Search")
},
leadingIcon = {
Icon(imageVector = Icons.Default.Search, contentDescription = null)
}
) {
// this is a column scope
// all the items are displayed vertically
historyItems.forEach { historyItem ->
Row(modifier = Modifier.padding(all = 16.dp)) {
Icon(
modifier = Modifier.padding(end = 12.dp),
imageVector = Icons.Default.History, contentDescription = null
)
Text(text = historyItem)
}
}
}
}
Output:

This is all about the Search Bar in Material 3 Jetpack Compose. I hope you have learned something new. If you have any doubts, leave a comment below.
Related Articles:
References: