
In this article, we’ll learn how to implement the bottom navigation with screens in Jetpack Compose.
Prerequisites:
We’ll create the following UI in this article.

Let’s get started.
First, create an empty Compose project and add the following dependencies in the app-level gradle file:
// for navigation
implementation "androidx.navigation:navigation-compose:2.7.2"
// for icons
// 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 and add the following code:
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
YourProjectNameTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
AppUI()
}
}
}
}
}
// we add scaffold here
@Composable
fun AppUI() {
}
// bottom bar implementation
@Composable
fun MyBottomBar(navController: NavHostController) {
}
Next, create the following files in your project:
- HomeScreen.kt
- ProfileScreen.kt
- SettingsScreen.kt
- Screen.kt (sealed class)
- NavGraph.kt

We added 3 files: HomeScreen, ProfileScreen, and SettingsScreen. They represent the corresponding screens (destinations).
The Screen is a sealed class. It is used to store the list of the screens.
In the NavGraph, we add the navigation graph.
Let’s display the screen name using a Text() composable. Add the following code in the corresponding files:
HomeScreen.kt:
@Composable
fun HomeScreen() {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text(
text = "Home Screen"
)
}
}
ProfileScreen.kt:
@Composable
fun ProfileScreen() {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text(text = "Profile Screen")
}
}
SettingsScreen.kt:
@Composable
fun SettingsScreen() {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text(
text = "Settings Screen"
)
}
}
Next, open the Screen.kt and paste the following code:
sealed class Screen(val route: String, val name: String, val icon: ImageVector) {
object Home: Screen(route = "home_screen", name = "Home", icon = Icons.Default.Home)
object Profile: Screen(route = "profile_screen", name = "Profile", icon = Icons.Default.Person)
object Settings: Screen(route = "settings_screen", name = "Settings", icon = Icons.Default.Settings)
}
It is a sealed class with 3 objects. Each object represents a screen. There are 3 parameters:
- route – It is used to identify the screen.
- name – The name of the screen. It is displayed on the Bottom Bar.
- icon – The icon representing the screen. It is also displayed on the Bottom Bar.
Next, we need to set the navigation graph. It contains all the screens (destinations) along with the logical connections between them. Open the NavGraph.kt and add the following code:
@Composable
fun SetupNavGraph(navController: NavHostController) {
NavHost(
navController = navController,
startDestination = Screen.Home.route
) {
composable(
route = Screen.Home.route
) {
HomeScreen()
}
composable(
route = Screen.Profile.route
) {
ProfileScreen()
}
composable(
route = Screen.Settings.route
) {
SettingsScreen()
}
}
}
There are two important things here: the Nav Controller and the Nav Host.
The Nav Controller is the central API for the Navigation component. It is used to keep track of the back stack. When you open a Screen, it is added to the Android back stack. Using the nav controller, we can go back to the previous screen, get the number of screens in the back stack, etc.
The Nav Host is used to define the navigation graph. It takes the startDestination parameter, which specifies the first screen that should be displayed when the app starts. We use the composable() method to add the destinations. There are three screens in our app. We added three composable() methods for each one.
We have set up the screens and navigation graph. Next, go to MainActivity and add the following code in the AppUI().
@Composable
fun AppUI() {
val navController = rememberNavController()
Scaffold(
bottomBar = { MyBottomBar(navController) }
) { paddingValues ->
Column(
modifier = Modifier
.padding(paddingValues = paddingValues)
.fillMaxSize()
) {
SetupNavGraph(navController = navController)
}
}
}
First, we created a state variable using the rememberNavController() method. Next, we added scaffold layout and SetupNavGraph() as its content.
Open MyBottomBar() and add the following code:
@Composable
fun MyBottomBar(navController: NavHostController) {
val navigationItems = listOf(
Screen.Home,
Screen.Profile,
Screen.Settings
)
var selectedScreen by remember {
mutableIntStateOf(0) // or use mutableStateOf(0)
}
NavigationBar {
navigationItems.forEachIndexed { index, screen ->
NavigationBarItem(
icon = { Icon(imageVector = screen.icon, contentDescription = null) },
label = { Text(text = screen.name) },
selected = (selectedScreen == index),
onClick = {
// this if condition keeps only one screen in the back stack
if (navController.currentBackStack.value.size >= 2) {
navController.popBackStack()
}
selectedScreen = index
navController.navigate(screen.route)
}
)
}
}
}
First, we created a list of navigation items. The selectedScreen variable is used to highlight the current destination on the bottom bar. We added the NavigationBar and its items using the NavigationBarItem() method.
If you don’t want to use the selectedScreen, add the following code to the NavigationBarItem()‘s selected parameter:
selected = navController.currentDestination?.route == screen.route
I tried the code, but there is a problem. The selected item is not getting highlighted visually. So, use the selectedScreen variable.
Now, run the project. You should see the following output:

This is all about implementing the bottom navigation with screens in Jetpack Compose. I hope you have learned something new. If you have any doubts, leave a comment below.
Related Articles:
References: