Building Production-Ready Navigation with the Mapbox UX Framework for Android
Overview
Building a navigation app from scratch is a massive undertaking. Traditionally, developers had to manually coordinate route fetching, camera transitions, voice instructions, and complex UI states. The
Prerequisites
To follow this guide, you should be comfortable with
- Public Token: Used for accessing map tiles and direction services.
- Secret Token: Required to download SDK dependencies from the private Mapbox Maven repository.
Key Libraries & Tools
- UX Framework (Dash): The primary high-level library containing pre-built UI components like search bars, guidance banners, and maneuver lists.
- Core SDK: The underlying engine that handles routing logic and map rendering.
- Configuration API: A tool for toggling features like 3D mode or street labels without writing custom UI code.
- Customization API: The interface for overriding default styles, icons, and fonts or injecting custom Jetpack Composeviews.
- Coordination API: Allows developers to programmatically manipulate the navigation state through the
DashController.

Code Walkthrough
1. Initializing the Framework
Unlike the Core SDK, which requires manual assembly, the UXF (internally referred to as Dash) is initialized globally within your Application class. This ensures the navigation services are ready before the user ever sees a map.
// In your Application class
override fun onCreate() {
super.onCreate()
// Dash is the internal shorthand for the UX Framework
dashInit(
context = this,
accessToken = getString(R.string.mapbox_access_token)
)
}
2. Implementing the Navigation Fragment
To display the interface, you instantiate the DashNavigationFragment. This single fragment handles the transition between different navigation states: Free Drive, Search, Preview, and Active Guidance.
// In your MainActivity
val navigationFragment = DashNavigationFragment()
supportFragmentManager.beginTransaction()
.replace(R.id.container, navigationFragment)
.commit()
3. Configuring Features with the UI Builder
You can modify the default behavior using the UIBuilder. For example, enabling a 3D perspective toggle in the camera controller requires only a few lines within a lambda after the initialization call.
UIBuilder {
// Enable the 3D perspective option in the camera toggle button
freeDriveCamera3DModeEnabled = true
// Always show the current street name at the bottom of the screen
streetLabelState = StreetLabelState.ALWAYS
}
4. Customizing UI with Jetpack Compose
The true strength of UXF lies in its extensibility. If you want to replace the standard search panel with a custom one, you use the setSearchPanel method on the DashFragment. This allows you to inject
navigationFragment.setSearchPanel { modifier, state ->
// Custom Compose Row replacing the default search bar
Row(modifier = modifier) {
IconButton(onClick = { state.onHomeClick() }) {
Icon(Icons.Default.Home, contentDescription = "Home")
}
IconButton(onClick = {
// Use DashController to trigger specific internal actions
dashController.openSearch(query = "Coffee")
}) {
Icon(Icons.Default.ShoppingCart, contentDescription = "Search Coffee")
}
}
}
Syntax Notes
- Dash Naming Convention: Throughout the API, you will see the prefix
dash(e.g.,dashInit,DashController). This is the internal name for the UX Framework. - Lambda Configuration: The SDK uses a DSL-style configuration pattern. By passing a lambda to
UIBuilder, you are interacting with a singleton state that the fragments observe. - State Hoisting: When overriding UI components, the framework provides a
stateobject. This object contains necessary callbacks (likeonHomeClick) so your custom UI can still trigger standard navigation behaviors.
Practical Examples
- Multi-Stop Routing: The UXF includes a built-in "Edit Trip" state. Users can tap a pencil icon to reorder waypoints, such as moving a gas station stop before a coffee shop stop, and the framework automatically recalculates the route.
- Contextual Search: When approaching a destination like an airport, the search tool can prioritize specific terminals or parking lots rather than generic results.
- EV Routing: The framework can be configured to display charging stations and monitor battery levels if integrated with vehicle data.
Tips & Gotchas
- Core vs. UXF: Do not try to mix MapboxCore SDK components with UXF components for the same feature. If you use UXF for guidance, let it handle the routing. While you can call Core APIs for low-level data, the UI state is best managed by the UXF to avoid synchronization bugs.
- Token Security: Always store your Secret Token in a
local.propertiesfile. Never hardcode it in yourbuild.gradleor commit it to version control, as it grants access to paid Mapbox downloads. - Form Factors: UXF is responsive. The same code used for a 10-inch vehicle head unit will automatically adjust its layout for a vertical smartphone screen, though you should test specific touch targets on smaller devices.