# Navigator Overview

In compose\_bloc the UI is split in [Screens](https://beyondeye.gitbook.io/compose-bloc/navigator-documentation/navigator-overview/screen) and you navigate between the UI Screens with a [Navigator](https://beyondeye.gitbook.io/compose-bloc/navigator-documentation/navigator-overview/navigator).  compose\_bloc make extensive use of [CompositionLocal ](https://developer.android.com/jetpack/compose/compositionlocal)data so that we can scope data to a specific part of the tree of composable calls that defines the UI.  This also allows us to handle the lifecycle of Screens and Navigators that defines the UI of the app.

### RootNavigator

We start by defining a `RootNavigator` for some Android Activity (or for some Compose Desktop Window):

```kotlin
class MainScreen: Screen {
    @Composable
        override fun Content() {
            //... main screen implementation here
        }
}

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            //*IMPORTANT* need to use RootNavigator to initialize root navigator for activity, not as in original voyager
            RootNavigator(MainScreen())
        }
    }
}
```

####

### LocalNavigator

Then in `MainScreen` `Content()` composable function and all its Composable subtree, we can access the navigator with `LocalNavigator.current` or `LocalNavigator.currentOrThrow`

```kotlin
class MainScreen: Screen {
    @Composable
    override fun Content() {
        val navigator= LocalNavigator.currentOrThrow
        //...
    }
}
```

### `renderComposableWithNavigator`  for Compose Web

For compose Web instead of `RootNavigator`  you need to mount the composition at some HTML element  using method `renderComposableWithNavigator` instead of the usual method  `renderComposable:`

```kotlin
class MainScreen: Screen {
    @Composable
    override fun Content() {
		//,,, screen content implementation here
    }
}

fun main() {
    renderComposableWithNavigator
        (screens = listOf(MainScreen()),
         rootElementId = "root")
}
```

For compose Web in addition to `LocalNavigator`  also the `DOMScope` for the HTML Element to which the navigator was bound, is made available with the CompositionLocal variable `LocalDomScope .`

### Basic Navigator Operations

We can use the  navigator instance to push new screens into the stack, or popping the current one if we want to go back to a previous screen.&#x20;

```kotlin
class Screen1:Screen {
    @Composable
    override fun Content() {
        //... content for Screen 1 here
    }
}
class MainScreen2: Screen {
    @Composable
    override fun Content() {
        val navigator= LocalNavigator.currentOrThrow
        Column {
            Button(onClick={ navigator.push(Screen1())}) { Text("click to open screen1") }
            Button(onClick={ navigator.pop() }) { Text("click to close this screen") }
        }
    }
}
```

### Navigator and OnBackPressed() events

Navigator has integrated handling of `OnBackPressed()` events. In other words when the users navigate away from a screen (pressing the back button on Android), this is handled by calling `navigator.pop()`  for the local navigator or its parent navigator if the local navigator has no screen that can be popped.&#x20;

It is also possible to override handling of `OnBackPressed()` events by specifying a custom handler  in the definition of the navigator. For example, for the `RootNavigator` we can write

```kotlin
setContent {
    RootNavigator(
        screen = MainScreen(),
        onBackPressed = { currentScreen ->
            //return true to pop the current screen, or false otherwise.
            false // won't pop the current screen
            // true will pop, default behavior
        }
        // To disable integration of handling of onBackPressed, set onBackPressed to null
        // onBackPressed = null
    )
}
```

### Nested Navigators&#x20;

For more complex navigation scenarios, for example for a screen with sub screens with each sub screen with an independent navigation stack, like a screen with tabs, with each tab with an independent navigation stack,  we can define nested navigators

```kotlin
setContent {
    RootNavigator(ScreenA) { navigator0 ->
        println(navigator.level)
        // 0
        println(navigator.parent == null)
        // true
        Navigator(ScreenB) { navigator1 ->
            println(navigator.level)
            // 1
            println(navigator.parent == navigator0)
            // true
            Navigator(ScreenC) { navigator2 ->
                println(navigator.level)
                // 2
                println(navigator.parent == navigator1)
                // true
            }
        }
    }
}
```

Note that usage of `RootNavigator`  is required only for the top Navigator of the current Activity

### Router and path-based navigation.

{% hint style="info" %}
path-based navigation was not supported in the original voyager library. Its implementation is derived from [routing-compose](https://github.com/hfhbd/routing-compose) .
{% endhint %}

Path-based navigation (i.e. navigation to a `Screen` with an `URL` ), is very natural for web apps, but is actually very useful for all platforms, for two main reasons:

* *support for deep links*: for app deep links we need a way to associate a Screen to an URL
* *decoupling of an app into independent components:*  for big applications, where multiple features are developed independently in multiple modules, there is usually central module that is the only one linked against all other modules, that implement a router that allows to navigate to Screens of any of the modules without the need of knowing anything of the other modules except the URL of the target screen.

We take a slightly different approach from other navigation libraries like the official Android Compose navigation library, and also [routing-compose](https://github.com/hfhbd/routing-compose) : In our implementation routing is not part of the composition. It is instead a separate operation that it is executed outside the composition that take as input an URL and return a `Screen` that is then pushed into the navigation stack. This way we gain a better separation between UI rendering and routing logic. Let's see an example.
