Compose Destinations

repository·main·Indexed 25 days ago

https://github.com/raamcosta/compose-destinations

A KSP code generation library for Jetpack Compose that simplifies navigation by automating the creation of navigation graphs, destinations, and argument handling. It provides type-safe navigation and eliminates boilerplate for routes, NavType, bundles, and strings while remaining compatible with official Jetpack Compose Navigation APIs.

Tokens
2.2K
Snippets
6
Records
11
Agent score
36%

What's inside Compose Destinations

  1. Overview of Compose Destinations

    main
    Compose Destinations is a KSP library that processes annotations to generate type-safe code for Jetpack Compose Navigation. It eliminates the need to manually write boilerplate code for routes, NavType, bundles, and strings, while remaining compatible with the official Jetpack Compose Navigation APIs.
  2. Define a screen destination with @Destination

    main

    To define a screen as a destination, annotate your Composable function with @Destination<RootGraph>. You can specify which navigation graph the destination belongs to by replacing RootGraph with your custom graph name. You can also mark a destination as the start destination using start = true.

    @Destination<RootGraph> // sets this as a destination of the "root" nav graph
    @Composable
    fun ProfileScreen() { /*...*/ }
    
    @Destination<RootGraph>(start = true) // sets this as the start destination of the "root" nav graph
    @Composable
    fun HomeScreen(navigator: DestinationsNavigator) { /*...*/ }
  3. Set up the DestinationsNavHost

    main

    To enable navigation in your application, add the DestinationsNavHost call. Use the generated NavGraphs object to provide the navigation graph. If you used <RootGraph> in your annotations, you will access it via NavGraphs.root.

    DestinationsNavHost(navGraph = NavGraphs.root)
  4. Install the KSP plugin for Compose Destinations

    main

    To use Compose Destinations, you must add the KSP (Kotlin Symbol Processing) plugin to your project. The version of the KSP plugin must match your project's Kotlin version. You can find compatible versions on the KSP releases page.

    For example, if you are using Kotlin 1.9.22, you should use KSP version 1.9.22-1.0.17.

    Groovy (build.gradle)

    plugins {
        //...
        id 'com.google.devtools.ksp' version '1.9.22-1.0.17' // Depends on your kotlin version
    }

    Kotlin DSL (build.gradle.kts)

    plugins {
        //...
        id("com.google.devtools.ksp") version "1.9.22-1.0.17" // Depends on your kotlin version
    }
    plugins {
        //...
        id 'com.google.devtools.ksp' version '1.9.22-1.0.17' // Depends on your kotlin version
    }
  5. Add navigation arguments to a destination

    main

    Add arguments directly to the Composable function declaration. Compose Destinations supports several types out of the box:

    • Parcelable
    • Serializable
    • Enum
    • Classes annotated with @kotlinx.serialization.Serializable
    • Arrays and ArrayLists of the above types.

    Required arguments are defined as standard parameters, while optional arguments can have default values.

    @Destination<RootGraph>
    @Composable
    fun ProfileScreen(
       id: Int, // <-- required navigation argument
       groupName: String?, // <-- optional navigation argument
       isOwnUser: Boolean = false // <-- optional navigation argument
    ) { /*...*/ }
  6. Add Compose Destinations dependencies

    main

    Add the core and KSP dependencies to your module. Choose a version that matches your Compose version based on the following mapping:

    Compose VersionRecommended Dependency Version Prefix
    1.1.x1.5
    1.2.x1.6
    1.3.x1.7
    1.4.x1.8
    1.5.x1.9
    1.6.x1.10 OR 2.0
    1.7.x1.11 OR 2.1
    1.8.x2.2
    1.9.x2.3

    Groovy (build.gradle)

    implementation 'io.github.raamcosta.compose-destinations:core:<version>'
    ksp 'io.github.raamcosta.compose-destinations:ksp:<version>'
    
    // V2 only: for bottom sheet destination support
    implementation 'io.github.raamcosta.compose-destinations:bottom-sheet:<version>'

    Kotlin DSL (build.gradle.kts)

    implementation("io.github.raamcosta.compose-destinations:core:<version>")
    ksp("io.github.raamcosta.compose-destinations:ksp:<version>")
    
    // V2 only: for bottom sheet destination support
    implementation("io.github.raamcosta.compose-destinations:bottom-sheet:<version>")

    Note for Wear OS: Replace the core dependency with io.github.raamcosta.compose-destinations:wear-core:<version> to use Wear Compose Navigation internally.

    implementation 'io.github.raamcosta.compose-destinations:core:<version>'
    ksp 'io.github.raamcosta.compose-destinations:ksp:<version>'
    
    // V2 only: for bottom sheet destination support, also add
    implementation 'io.github.raamcosta.compose-destinations:bottom-sheet:<version>'
  7. Avoid direct NavController usage in Compose 1.7+

    main

    When using Compose 1.7 or higher, or if you encounter kotlinx.serialization.SerializationException: Serializer for class 'DirectionImpl' is not found, you must avoid calling NavController.navigate because the official library's type-safe APIs shadow the library's extension functions. Use DestinationsNavigator instead.

    To get a DestinationsNavigator:

    • In a Composable screen: Pass DestinationsNavigator as a parameter to your annotated screen.
    • In a Composable (top-level): Use navController.rememberDestinationsNavigator().
    • Non-Composable context: Use navController.toDestinationsNavigator().

    Additionally, remove any direct dependency on androidx.navigation:navigation-compose to avoid version conflicts.

  8. Navigate using DestinationsNavigator (Compose 1.7+ / Version 2.1.0-beta02+)

    main

    If you are using Compose 1.7 or higher (specifically versions 1.11.3-alpha / 2.1.0-beta02 and above), do not call NavController.navigate directly. The official Jetpack Compose Navigation type-safe APIs shadow the library's extension functions.

    Instead, use DestinationsNavigator. You can obtain a navigator in the following ways:

    1. Inside a specific screen: Receive a DestinationsNavigator directly as a parameter in your annotated screen Composable.
    2. Top-level navigation (e.g., around DestinationsNavHost or bottom nav bars):
      • In a Composable: Use navController.rememberDestinationsNavigator().
      • Outside a Composable: Use navController.toDestinationsNavigator().

    Important: Do not depend on androidx.navigation:navigation-compose directly; Compose Destinations provides the correct version transitively.

  9. Navigate using generated Destination objects

    main

    After building the project (or running the KSP task), a [ComposableName]Destination object is generated for each annotated Composable. Use the invoke method of this object with the required typed arguments to navigate via a DestinationsNavigator.

    @Destination<RootGraph>(start = true)
    @Composable
    fun HomeScreen(
       navigator: DestinationsNavigator
    ) {
       /*...*/
       navigator.navigate(ProfileScreenDestination(id = 7, groupName = "Kotlin programmers"))
    }
  10. Use DefaultSerializableNavTypeSerializer for Serializable arguments

    main

    The DefaultSerializableNavTypeSerializer is the fallback serializer used by the library when you pass a Serializable object as a navigation argument. It automatically converts Serializable objects into Base64 strings for route representation and parses them back into objects during navigation.

    You do not need to manually instantiate this class; the library uses it automatically if you do not provide a custom serializer annotated with @NavTypeSerializer for your specific type.

  11. Configure navigation options with DestinationsNavOptionsBuilder

    main

    Use DestinationsNavOptionsBuilder to configure navigation options in a way that is compatible with Compose Destinations. It provides a wrapper around the standard Jetpack NavOptionsBuilder but allows you to use Compose Destinations types like Route or Direction for popping up to specific destinations.

    Key properties and methods:

    • launchSingleTop: Boolean flag to prevent multiple copies of the same destination from being placed on top of the back stack.
    • restoreState: Boolean flag to restore the state of the destination being navigated to.
    • popUpToRoute: Returns the route string that the back stack will be popped up to.
    • popUpTo(route: RouteOrDirection, popUpToBuilder: PopUpToBuilder.() -> Unit): Pops the back stack up to the specified Route or Direction.