Implement navigation in Jetpack Compose using Navigation 3. Use when asked to build state-driven navigation, manage back stacks, scope ViewModels, implement adaptive layouts, or migrate from Navigation Compose.
npx skills add https://github.com/new-silvermoon/awesome-android-agent-skills --skill navigation3
Implement state-driven navigation in Jetpack Compose using Navigation 3. Unlike Navigation Compose, Navigation 3 models navigation as application state rather than through a NavController. This skill covers navigation keys, back stack management, ViewModel scoping, entry decorators, adaptive layouts, deep links, animations, state restoration, and testing.
Add the Navigation 3 dependencies:
// build.gradle.kts
dependencies {
implementation("androidx.navigation3:navigation3-runtime:1.0.0-alpha08")
implementation("androidx.navigation3:navigation3-ui:1.0.0-alpha08")
// Lifecycle integration
implementation("androidx.lifecycle:lifecycle-viewmodel-navigation3:2.9.2")
// Serialization
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.1")
}
// Enable serialization plugin
plugins {
kotlin("plugin.serialization") version "2.2.0"
}
Navigation destinations are represented by immutable serializable objects.
import kotlinx.serialization.Serializable
@Serializable
data object Home
@Serializable
data class Profile(
val userId: String
)
@Serializable
data class Product(
val productId: String,
val showReviews: Boolean = false
)
@Serializable
data object Settings
Keys become your navigation state.
Navigation 3 replaces NavController with a mutable state back stack.
@Composable
fun MyApp() {
val backStack = remember {
mutableStateListOf<Any>(Home)
}
AppNavDisplay(backStack)
}
@Composable
fun AppNavDisplay(
backStack: SnapshotStateList<Any>
) {
NavDisplay(
backStack = backStack,
onBack = {
if (backStack.size > 1) {
backStack.removeLast()
}
}
) { key ->
when (key) {
Home ->
HomeScreen(
onProfileClick = {
backStack += Profile(it)
}
)
is Profile ->
ProfileScreen(
userId = key.userId
)
is Product ->
ProductScreen(
productId = key.productId,
showReviews = key.showReviews
)
Settings ->
SettingsScreen()
}
}
}
backStack += Profile("user123")
backStack.removeLast()
backStack[backStack.lastIndex] = Home
backStack.clear()
backStack += Home
while (backStack.size > 1) {
backStack.removeLast()
}
Arguments already exist inside the navigation key.
when (val key = currentKey) {
is Profile -> {
ProfileScreen(
userId = key.userId
)
}
is Product -> {
ProductScreen(
productId = key.productId
)
}
}
// CORRECT
backStack += Profile(user.id)
// Fetch object inside ViewModel
class ProfileViewModel(
savedStateHandle: SavedStateHandle,
repository: UserRepository
) : ViewModel() {
val profile = savedStateHandle.toRoute<Profile>()
val user =
repository.getUser(profile.userId)
}
// INCORRECT
backStack += User(...)
backStack += ProductRepository(...)
backStack += ProductViewModel(...)
Navigation 3 scopes ViewModels using entry decorators.
NavDisplay(
backStack = backStack,
entryDecorators = listOf(
rememberSceneSetupNavEntryDecorator(),
rememberSavedStateNavEntryDecorator(),
rememberViewModelStoreNavEntryDecorator()
)
) { key ->
// destinations
}
class ProfileViewModel(
savedStateHandle: SavedStateHandle
) : ViewModel() {
val profile =
savedStateHandle.toRoute<Profile>()
}
Navigation 3 uses decorators to attach lifecycle functionality.
rememberSceneSetupNavEntryDecorator()
Creates the navigation scene for each entry.
rememberSavedStateNavEntryDecorator()
Automatically restores destination state after process recreation.
rememberViewModelStoreNavEntryDecorator()
Scopes ViewModels to each navigation entry.
Navigation 3 integrates with Material Adaptive layouts.
NavDisplay(
backStack = backStack,
sceneStrategy = rememberListDetailSceneStrategy()
)
Use adaptive scene strategies to automatically switch between:
Deep links should resolve into navigation keys.
fun handleDeepLink(uri: Uri) {
val userId =
uri.lastPathSegment ?: return
backStack += Profile(userId)
}
Avoid manually constructing route strings.
Navigation transitions are defined using scene transitions.
NavDisplay(
backStack = backStack,
transitionSpec = {
fadeIn() togetherWith fadeOut()
}
)
Navigation 3 animation APIs may evolve while in alpha.
Navigation keys are serializable and automatically restored.
val backStack = rememberSaveable(
saver = navBackStackSaver()
) {
mutableStateListOf(Home)
}
Always ensure keys are serializable.
Navigation becomes simple because it is state-driven.
@Test
fun navigateToProfile() {
val backStack =
mutableStateListOf<Any>(Home)
backStack += Profile("123")
assertEquals(
Profile("123"),
backStack.last()
)
}
Compose UI tests can verify screen rendering by inspecting the current back stack.
| Navigation Compose | Navigation 3 |
|-------------------|--------------|
| NavController | Mutable back stack |
| NavHost | NavDisplay |
| navigate() | backStack += Key |
| popBackStack() | removeLast() |
| String routes | Serializable keys |
| composable() | when(key) |
| Navigation graph | State-driven destinations |
navigation/
AppNavigation.kt
NavigationKeys.kt
NavigationDisplay.kt
feature/
home/
profile/
settings/
rememberSaveable for state restorationToolkit for styling artifacts with a theme. These artifacts can be slides, docs, reportings, HTML landing pages, etc. There are 10 pre-set themes with colors/fonts that you can apply to any artifact that has been creating, or can generate a new theme on-the-fly.
Applies Anthropic's official brand colors and typography to any sort of artifact that may benefit from having Anthropic's look-and-feel. Use it when brand colors or style guidelines, visual formatting, or company design standards apply.
Suite of tools for creating elaborate, multi-component claude.ai HTML artifacts using modern frontend web technologies (React, Tailwind CSS, shadcn/ui). Use for complex artifacts requiring state management, routing, or shadcn/ui components - not for simple single-file HTML/JSX artifacts.
Suite of tools for creating elaborate, multi-component claude.ai HTML artifacts using modern frontend web technologies (React, Tailwind CSS, shadcn/ui). Use for complex artifacts requiring state management, routing, or shadcn/ui components - not for simple single-file HTML/JSX artifacts.
Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
Guidance for distinctive, intentional visual design when building new UI or reshaping an existing one. Helps with aesthetic direction, typography, and making choices that don't read as templated defaults.
Set up Tailwind CSS v4 in Expo with react-native-css and NativeWind v5 for universal styling
Use Expo DOM components to run web code in a webview on native and as-is on web. Migrate web code to native incrementally.
Take new-silvermoon/navigation3 from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.