Jetpack Compose Nested Navigation Best Practices

Destinations can be grouped into a nested graph to modularize a particular flow in your app’s UI. An example of this could be a self-contained login flow.

The nested graph encapsulates its destinations. As with the root graph, a nested graph must have a destination identified as the start destination by its route. This is the destination that is navigated when you navigate to the route associated with the nested graph.

Why Nested Navigations?

When your project is small or has fewer screen counts you can avoid nesting the navigation graph. but, when you have large projects and many contributors working on the same project that time you need to make a manageable and readable system for the navigation so that it can be managed easily in future.

Note: This is recommended for Large Projects

Let’s Start An Example

First thing first Don’t forget to add Navigation Dependency.

dependencies {
    val nav_version = "2.7.0"

    implementation("androidx.navigation:navigation-compose:$nav_version")
}

For better Routing and to avoid any typo errors we are using Sealed Class.

sealed class Screens(val route : String) {

    object Dashboard : Screens("dashboard")

    object Home : Screens("home"){
        object Login : Screens("login")
        object Register : Screens("register")
    }
}

Each NavController must be associated with a single NavHost composable. The NavHost links the NavController with a navigation graph that specifies the composable destinations that you should be able to navigate between. As you navigate between composables, the contentNavHost is automatically recomposed. Each composable destination in your navigation graph is associated with a route

Here is out NavHost

@Composable
fun NestedNavigationExample() {
    val navController = rememberNavController()
    NavHost(
        navController = navController,
        startDestination = Screens.Home.route
    ) {

        navigation(
            startDestination = Screens.Home.Login.route,
            route = Screens.Home.route
        ) {
            composable(route = Screens.Home.Login.route) {
                LoginScreen {
                    navController.navigate(it)
                }
            }
            composable(route = Screens.Home.Register.route) {
                RegisterScreen {
                    navController.navigate(it)
                }
            }
        }

        composable(route = Screens.Dashboard.route) {
            DashboardScreen {
                navController.navigate(it)

            }
        }
    }
}

Explanation

  1. composable is an extension function of GraphBuilder which holds your current screen.
  2. navigation is an extension function of GraphBuilder which holds another graph.

Here is all the screen you can check for Best navigation practice.

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DashboardScreen(navigateTo: (route: String) -> Unit) {
    Scaffold(topBar = {
        TopAppBar(
            title = { Text(text = "Dashboard") },
            colors = TopAppBarDefaults.topAppBarColors(containerColor = MaterialTheme.colorScheme.primary)
        )
    }) {
        Box(
            Modifier
                .padding(it)
                .fillMaxSize(), contentAlignment = Alignment.Center
        ) {
            Text(text = "Dashboard Screen Content")
        }
    }
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun LoginScreen(navigateTo: (route: String) -> Unit) {
    Scaffold(topBar = {
        TopAppBar(
            title = { Text(text = "Login") },
            colors = TopAppBarDefaults.topAppBarColors(containerColor = MaterialTheme.colorScheme.primary)
        )
    }) {
        Column(
            Modifier
                .padding(it)
                .fillMaxSize(),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Center
        ) {
            Button(onClick = {
                navigateTo(Screens.Dashboard.route)
            }) {
                Text(text = "Login")
            }
            Button(onClick = {
                navigateTo(Screens.Home.Register.route)
            }) {
                Text(text = "Register")
            }
        }
    }
}


@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun RegisterScreen(navigateTo: (route: String) -> Unit) {
    Scaffold(topBar = {
        TopAppBar(
            title = { Text(text = "Register") },
            colors = TopAppBarDefaults.topAppBarColors(containerColor = MaterialTheme.colorScheme.primary)
        )
    }) {
        Box(
            Modifier
                .padding(it)
                .fillMaxSize(), contentAlignment = Alignment.Center
        ) {
            Button(onClick = {
                navigateTo(Screens.Dashboard.route)
            }) {
                Text(text = "Register")
            }
        }
    }
}

That’s it. It’s Done Enjoy Compose.

🍴Check out the complete code on my GitHub Repository. ✍️ Hope this project really helps you.

Hope you enjoy coding Jetpack Compose 😁. Don’t forget to share 📨 and clap 👏.

Any Suggestions are welcome. If you need any help or suggestion for Code Checking I’ll help you. Follow me on LinkedInStackOverflow and Twitter For More Updates 🔔

Happy Compose !! 🚀

Leave a Comment