Nested Navigation Graphs in Jetpack Compose

Root Navigation Host

In the last article about modularized navigation, we created a NavHost that held each of our composable destinations in the form of `composable` references.

NavHost(
navController,
startDestination = NavigationDirections.Authentication.destination
) {
composable(NavigationDirections.Authentication.destination) {
Authentication(hiltNavGraphViewModel())
}
composable(NavigationDirections.Dashboard.destination) {
Dashboard(hiltNavGraphViewModel())
}
}
NavHost(
navController,
startDestination = NavigationDirections.Authentication.destination
) {
composable(NavigationDirections.Onboarding.destination) {
Onboarding(hiltNavGraphViewModel())
}
composable(NavigationDirections.Authentication.destination) {
Authentication(hiltNavGraphViewModel())
}
composable(NavigationDirections.ForgotPassword.destination) {
ForgotPassword(hiltNavGraphViewModel())
}
composable(NavigationDirections.Dashboard.destination) {
Dashboard(hiltNavGraphViewModel())
}
composable(NavigationDirections.Settings.destination) {
Settings(hiltNavGraphViewModel())
}
composable(NavigationDirections.CreateItem.destination) {
CreateItem(hiltNavGraphViewModel())
}
composable(NavigationDirections.EditItem.destination) {
EditItem(hiltNavGraphViewModel())
}
...
}

Declaring a Nested Navigation Graph

To tidy things up a bit here, we’re going to split out different parts of our navigation graph into their own separate sections.

navigation(...) {
composable(OnboardingDirections.authentication.destination) {
Authentication(
navController.hiltNavGraphViewModel(
route = OnboardingDirections.authentication.destination
)
)
}
composable(AuthenticationDirections.forgotPassword().destination){
ResetPassword(
navController.hiltNavGraphViewModel(
route =AuthenticationDirections.forgotPassword().destination
)
)
}
}
navigation(
startDestination =
AuthenticationDirections.authentication.destination
) {
composable(AuthenticationDirections.authentication.destination) {
Authentication(
navController.hiltNavGraphViewModel(
route = AuthenticationDirections.authentication.destination
)
)
}
...
}
object AuthenticationDirections {
val root = object : NavigationCommand {
override val arguments = emptyList<NamedNavArgument>()
override val destination = "authentication"
}
val authenticate = object : NavigationCommand {
override val arguments = emptyList<NamedNavArgument>()
override val destination = "authenticate"
}

val forgotPassword = object : NavigationCommand {
override val arguments = emptyList<NamedNavArgument>()
override val destination = "forgot_password"
}
}
navigation(
startDestination =
AuthenticationDirections.authenticate.destination,
route = AuthenticationDirections.root.destination
) {
...
}

Navigating to a Nested Navigation Graph

With this all in place, we can now perform navigation directly to a nested graph. This is done in the same way that we navigate to a composable destination, using the navigate command on our NavController reference.

navController.navigate(AuthenticationDirections.root.destination)

Defining the starting Navigation Graph

Back at the top-level of our navigation graph and the NavHost declaration, we have a startDestination which is used to declare the composable destination that is to be displayed when our graph is loaded. For this we are able to provide the route of a nested graph, meaning that one of our nested feature graphs will be used as the startDestination, and in turn the startDestination of that nested graph will then be the composable that is initially displayed.

NavHost(
navController,
startDestination = AuthenticationDirections.root.destination
)

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Joe Birch

Joe Birch

Android Engineering Lead at Buffer, Google Developer Expert for Android & Flutter - Passionate about mobile development and learning. www.joebirch.co