Skip to content

Feature request: Runtime Destination Style Customization #768

@MohamadJaara

Description

@MohamadJaara

Compose Destinations takes care of destination styles when the code is being compiled. It works fine for most situations, but not so well when the way a destination is shown needs to change based on run time variables.

For my use case I have, certain screens that are full-screen on phones should render as dialogs style on tablets. Today, the only way to achieve this is to copy past DefaultNavHostEngine directly replacing the style resolution logic with a custom one. That class is fragile and forces the project to use internal APIs, also it couples the consuming project to library internals, makes upgrading painful.

The same limitation applies to other runtime concerns:

  • Reduced-motion accessibility: disabling transitions globally when the user has enabled reduced motion.
  • Feature flags: changing how a destination is displayed based on a remote flag.
  • Deep-link filtering: stripping environment-specific deep links (e.g. staging-only URIs) at registration time.

None of these can be expressed through annotation parameters alone.

Suggested solution:

Adding something like DefaultEnginePolicy, an interface with three optional hooks:

Hook Purpose
resolveDestinationStyle(ctx) Override the style for a destination (e.g. Default -> Dialog)
resolveGraphTransitions(ctx) Override transition animations for a navigation graph
transformDeepLinks(ctx) Replace or filter the deep links registered for a route

Each hook receives a read-only context object containing the destination/graph metadata, the annotation-declared defaults, and any existing manual overrides. Returning null keeps the current behavior.

The resolution precedence is:

policy override  >  manual animateWith override  >  annotation-declared style

Usage

DestinationsNavHost(
    navGraph = NavGraphs.root,
    enginePolicy = object : DefaultEnginePolicy {
        override fun resolveDestinationStyle(ctx: DestinationStyleContext): DestinationStyle? {
            return if (isTablet && ctx.baseRoute in tabletDialogRoutes) {
                DestinationStyle.Dialog.Default
            } else {
                null // keep default behavior
            }
        }
    }
)

No custom engine, no fork, no breaking changes.

Tip

If you like this proposal, I would be more than happy to raise a PR implementing it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions