User interface

The Navigation SDK provides several pre-built UI components that you can use to build a complete user interface for a turn-by-turn navigation application. Drop components into your application using their default configuration or customize the components' behavior and appearance to create a completely unique experience for your users.

Use the drop-in UI

The Navigation SDK for iOS offers a complete drop-in UI, NavigationViewController.

NavigationViewController embeds a NavigationView that contains the following UI components with appropriate functionality included by default:

  1. InstructionsBannerView: Maneuver instructions
  2. InformationStackView: Additional maneuver instructions information
  3. BottomBannerViewController: Trip progress
  4. ResumeButton: Resume button
  5. WayNameLabel: Label for current way
  6. FloatingStackView: Camera, volume, and feedback buttons
  7. NavigationMapView: Map a displaying route line and user location
  8. SpeedLimitView: Speed limit
|         1          |  
|         2          |
| 8 |            |   |
+---+            | 6 |
|                |   |
|         7      +---+
|                    |
|                    |
|                    |
+------------+       |
|  4  ||  5  |       |
|         3          |

Present a navigation view controller

For an example of how to initialize NavigationViewController, see the Request a route section of the Installation guide.

Maneuver instructions

NavigationViewController uses logic from Mapbox Core Navigation to trigger a comprehensive system of visual and spoken instructions by default. There are default styling rules for visual instructions and default settings for voice instructions. Instructions can be customized to synchronize your application's behavior with instructions coming from the Mapbox Navigation SDK and customizing the style of visual instructions to fit with your application.

Default visual instructions

The default TopBannerViewController UI component shows maneuver instructions. It is refreshed by route progress events and displays the following pieces of information:

  • Primary visual instruction: Shows the name of the road, freeway, or exit of the next maneuver.
  • Secondary visual instruction (optional): Shows more information about the road, freeway, or exit if available.
  • Tertiary visual instruction (optional): Shows either the name of the road, freeway, or exit of the maneuver after the next maneuver if it will occur shortly after completing the next maneuver, or guides the user to drive in the appropriate lane if there are multiple lanes and an upcoming maneuver requires them to be in a specific lane.
  • Quaternary visual instruction (optional): In some regions, a graphical representation of the layout of a freeway exit.
  • Upcoming maneuver list: Shows a list of upcoming maneuvers excluding the current maneuver.

A user can also tap or swipe down on TopBannerViewController to view a full list of maneuvers for the trip.

Listen for changes to visual instructions

By default, visual instructions will be displayed when NavigationServiceDelegate.navigationService(_:didPassVisualInstructionPoint:routeProgress:) is called and Notification.Name.routeControllerDidPassVisualInstructionPoint is posted when the user passes the appropriate point at which to display a visual instruction. A visual instruction point occurs near the beginning of a step. There may be additional visual instruction points along the step as additional information, like turn lanes, become relevant.

You can use VisualInstructionDelegate.label(_:willPresent:as:) to adjust the predefined contents of visual instruction provided by the Directions API, but you cannot currently trigger an arbitrary message outside the visual instructions that are triggered by default.

func label(_ label: InstructionLabel, willPresent instruction: VisualInstruction, as presented: NSAttributedString) -> NSAttributedString? {   
    let range = NSRange(location: 0, length: presented.length)
    let mutable = NSMutableAttributedString(attributedString: presented)
    mutable.mutableString.applyTransform(.latinToKatakana, reverse: false, range: range, updatedRange: nil)
    return mutable

Listen for changes to spoken instructions

By default, spoken instructions will be played when NavigationServiceDelegate.navigationService(_:didPassSpokenInstructionPoint:routeProgress:) is called and Notification.Name.routeControllerDidPassSpokenInstructionPoint is posted when the user passes the appropriate point at which to announce a spoken instruction. A spoken instruction point occurs near the end of a step. There may be additional spoken instruction points, as time allows, at a comfortable distance before the end of the step and near the beginning of the step. A single spoken instruction point may correspond to an instruction about two successive maneuvers nearby.

You can also trigger arbitrary voice instructions by calling SpeechSynthesizer.speak(_:during:locale:).

Trip progress

Many navigation applications display data related to trip progress including the estimated time to arrival and the distance remaining. NavigationViewController includes a trip progress UI. The SDK uses the RouteProgress class to hold information about your user's progress along a route. The information is then used to display indicators of trip progress on the device's screen. Read more about the information included in the route progress object in the Route progress guide.

The default BottomBannerViewController UI component illustrates the user's progress along a route. It is refreshed by route progress events and displays:

  • Estimated time to arrival
  • Distance remaining
  • Estimated time remaining


While applications using the Navigation SDK don't have to include a map, many use cases will require maps to provide an appropriate navigation experience to your users. By default, NavigationViewController uses the Mapbox Maps SDK for Android to display routes on a map and show the user's location on the map throughout their trip to provide both navigation-related context and nearby places that may be of interest to the driver.

Read more about using maps in the Maps for navigation guide.

Speed limit

The speed limit UI included in NavigationViewController, SpeedLimitView, displays the speed limit of the road the user is currently traveling on.

Map buttons

NavigationViewController includes several buttons for the user to control the behavior of the application including:

Route overview
Zoom out to an overview of the full route at any time during navigation.
Resume navigation
Zoom back in to the current location after viewing the route overview or after panning around the map manually.
Volume control
Mute or unmute voice instructions.
Provide route or map feedback.

Customize NavigationViewController

App styling

When using NavigationViewController, it's possible to apply custom fonts and colors to various parts of the UI. The easiest way to find elements and their class name to style is to use the Debug View Hierarchy feature in Xcode.

  1. While running your app, select the Debug View Hierarchy button.
  2. Select the view you wish to style.
  3. On the right side of your screen, note the class name.
  4. Apply your styling:
DistanceLabel.appearance(whenContainedInInstancesOf: [InstructionsBannerView.self]).unitTextColor = .red

Remember to apply such styling in Style.apply() method.

It is also helpful to view the default styling applied by the DayStyle.

Spoken instruction override

Override a spoken instruction with a custom instruction.

func voiceController(_ voiceController: RouteVoiceController, willSpeak instruction: SpokenInstruction, routeProgress: RouteProgress) -> SpokenInstruction? {
    return SpokenInstruction(distanceAlongStep: instruction.distanceAlongStep, text: "New Instruction!", ssmlText: "<speak>New Instruction!</speak>")


For customizing the language used in visual and spoken instructions, see Localization and internationalization.

Build a custom UI

If you want to build a completely customizable turn-by-turn experience, you can use some of the Navigation SDK's UI components used in NavigationViewController individually or build your own components from scratch.

Top banner

The Navigation SDK offers InstructionsCardViewController as a prebuilt alternative to the default TopBannerViewController to display maneuver instructions as a “card” resembling a user notification. In InstructionsCardViewController, the next maneuver is partially visible on one side of the view and swiping to one side reveals the full maneuver.

Replace TopBannerViewController with InstructionsCardViewController when using NavigationViewController:

let instructionsCardCollection = InstructionsCardViewController()
let navigationOptions = NavigationOptions(bottomBanner: instructionsCardCollection)
let navigationViewController = NavigationViewController(for: response, routeIndex: 0, routeOptions: routeOptions, navigationOptions: navigationOptions)
instructionsCardCollection.navigationViewController = navigationViewController
Custom top banner contents

You can also replace the default TopBannerViewController with a custom view that shows anything you'd like to occupy the top banner position. Create your custom view:

class CustomTopBannerViewController: ContainerViewController, CustomBottomBannerViewDelegate {
  // build custom view

Then use the code above, but substitute your CustomTopBannerViewController for InstructionsCardViewController.

Bottom banner

When using NavigationViewController you can replace the default BottomBannerViewController that shows trip progress with a custom view that shows trip progress or anything else you'd like to occupy the bottom banner position.

Start by creating your custom view:

class CustomBottomBarViewController: ContainerViewController, CustomBottomBannerViewDelegate {
  // build custom view

Then pass your custom implementations of the bottom banner to NavigationOptions. If you do not specify a bottomBanner explicitly, the default BottomBannerViewController will be used by default.

let bottomBanner = CustomBottomBarViewController()
let navigationOptions = NavigationOptions(bottomBanner: bottomBanner)
let navigationViewController = NavigationViewController(for: response, routeIndex: 0, routeOptions: routeOptions, navigationOptions: navigationOptions)
bottomBanner.navigationViewController = navigationViewController
Custom banners

Substitute the default top and bottom banners with custom view controllers.

Spoken instructions

An application can call RouteVoiceController.speak(_:) at any time to interrupt any in-progress spoken instruction with a custom spoken instruction.

For more information on supported SSML tags see Amazon's SSML Tags Supported by Amazon Polly guide.