Tanish Azad
10/01/2026, 2:41 PM讗诇讬讛讜 讛讚住
10/01/2026, 6:30 PMTanish Azad
10/02/2026, 1:57 AM/user/:id
So a navigation3-browser url will look like <http://example.com/#user/?id=taz|example.com/#user/?id=taz>
But with compose-web-navigator it'll look like the usual <http://example.com/user/taz|example.com/user/taz>Tanish Azad
10/02/2026, 4:51 AM讗诇讬讛讜 讛讚住
10/02/2026, 6:16 AMJoost Klitsie
10/05/2026, 7:42 AMTanish Azad
10/05/2026, 9:47 AMJoost Klitsie
10/05/2026, 10:07 AMconfig.devServer.historyApiFallback = true; and then I think it works.
then afterwards you would have to get the current path and then parse it into your destination, which is the annoying part with nested navigation, if you have nested NavDisplays.
After this, I made my own helper method to create the url from back stack entries and I was overriding the contentKey:
NavDisplay(
backStack = someBackStack,
entryDecorators = listOf(rememberViewModelStoreNavEntryDecorator()),
) { entry ->
// I like this way to define Nav entries so we can pattern match with when(..)
when (entry) {
is SomeState.Home -> NavEntry(entry, "home") { // <-- we pass "home" as contentKey
HomeScreen()
}
is SomeState.About -> NavEntry(entry, "about") { // <-- we pass "about" as contentKey
AboutScreen()
}
}
}
Now we successfully set the content key to our nav entry. Now we just have to put that stuff back into the url using HierarchicalBrowserNavigation from terrakok
Here I do have to say that I have nested nav displays, so it should go through the stack and then build up the url from the nested graph.
So lets say I have a home screen, with a bottom navigation and 3 different pages, home/overview, home/settings, home/about or whatever, it should recursively find these.
By relying on the contentKey we can customly name destinations. So you can also set a content key like: NavEntry(entry, "details/${entry.id}")
@Composable
fun SetupBrowserHistory() {
val dispatcher = LocalNavigationEventDispatcherOwner.current?.navigationEventDispatcher ?: return
val history by dispatcher.history.collectAsState()
HierarchicalBrowserNavigation(
currentDestinationName = {
val fullHistory = history.mergedHistory.flatMap { info ->
buildList {
if (info is SceneInfo<*>) {
info.scene.entries.lastOrNull()?.contentKey?.toString()?.let(::add)
?: add(info.scene.key.toString())
} else {
info::class.simpleName
}
}
}
fullHistory
.filterIndexed { index, contentKey ->
fullHistory.getOrNull(index + 1)?.startsWith("$contentKey/", false) != true
}
.joinToString("/")
},
)
}
As said, the shitty part is to parse the original url into a nested graph. For that I can't share the code because it is very specific. Something with getting the path and then passing it down until there are no more consumers.