Map styles
Map Styles in the TomTom Maps SDK define the visual appearance and data presentation of maps. A style is a set of sources and layers. This guide covers:
- Built-in styles: TomTom's pre-defined styles, and switching between them at runtime.
- Custom styles: your own, loaded from a URL or as JSON.
- Style parts: traffic and hillshade, included or left out.
- Map language: the language of the map labels.
Built-in styles
Basic styles
import { TomTomMap } from '@tomtom-org/maps-sdk/map';
// Light theme (default)
const map = new TomTomMap({
mapLibre: {
container: 'map'
},
style: 'monoLight'
});
// Dark theme
const map = new TomTomMap({
mapLibre: {
container: 'map'
},
style: 'monoDark'
});
// Satellite imagery with roads and labels
const map = new TomTomMap({
mapLibre: {
container: 'map'
},
style: 'satellite'
});
The full list of IDs is exported as standardStyleIDs: standardLight, standardDark, drivingLight, drivingDark, monoLight, monoDark and satellite.
Dynamic style switching
const map = new TomTomMap({ mapLibre: { container: 'map' } });
// Change style after map creation
map.setStyle('monoDark');
// ...
map.setStyle('drivingLight');
setStyle returns a promise that resolves once the new style has loaded and every SDK module has restored itself onto it. Awaiting it is optional, but it is the moment after which the map is safe to read and draw on again:
await map.setStyle('standardDark');
// map.mapReady is true again; routes, places and traffic are back on the new style
Keeping or dropping state
By default a style switch carries everything over: module data and configuration (routes, places, POI filters, traffic visibility…) and the style parts of the previous style (traffic, hillshade). Pass resetState: true for a clean switch instead:
// Carry everything over (default)
map.setStyle('standardDark');
// Clean switch: modules re-bind to the new style with default configuration and nothing shown,
// and only the style parts named in the new style are loaded
map.setStyle('standardDark', { resetState: true });
Both variants run the registered style change handlers (below); each handler learns which kind of switch it is from its context.resetState argument.
The map language is not SDK state, so neither variant touches it: it is re-applied to the new style either way, and only setLanguage changes it.
Passing the style that is already loaded runs the same lifecycle without reloading the style, so setStyle(currentStyle, { resetState: true }) is how you reset the SDK modules over the map you are already looking at.
Listening to style changes
Use addStyleChangeHandler to react when a style transition triggered by map.setStyle() begins or completes. This is the right hook for preserving custom layers, syncing UI state, or reinitializing anything that depends on the current style.
:::note
This handler only fires for setStyle calls on TomTomMap. It does not fire on initial map construction. For lower-level style lifecycle hooks — such as reacting to the initial style load or to any style-related MapLibre event — use map.mapLibreMap.on('styledata', ...) directly.
:::
import { TomTomMap, type StyleChangeHandler } from '@tomtom-org/maps-sdk/map';
const map = new TomTomMap({ mapLibre: { container: 'map' } });
const unsubscribe = map.addStyleChangeHandler({
onStyleAboutToChange: (context) => {
// Called before the style change begins — clean up anything tied to the current style
},
onStyleChanged: (context) => {
// Called after the new style is fully loaded — restore state, re-add layers, update UI.
// context.resetState tells you whether this is a clean switch (see above).
},
});
// Later, when the handler's owner is torn down:
unsubscribe();
Both callbacks are optional. Use only the one(s) you need. Handlers run in registration order, after the SDK's own modules have restored themselves.
Preserving custom MapLibre layers
For your own GeoJSON data, prefer CustomGeoJSONModule: it restores its sources, layers and images after every style change, and gives them SDK events.
Custom sources and layers added via map.mapLibreMap are removed when the style changes. Use onStyleAboutToChange to save their data and onStyleChanged to restore them:
import type { GeoJSONSource } from 'maplibre-gl';
let savedData: GeoJSON.FeatureCollection | null = null;
map.addStyleChangeHandler({
onStyleAboutToChange: () => {
const source = map.mapLibreMap.getSource('my-data') as GeoJSONSource | undefined;
if (source) {
savedData = source._data as GeoJSON.FeatureCollection;
}
},
onStyleChanged: () => {
if (savedData) {
map.mapLibreMap.addSource('my-data', { type: 'geojson', data: savedData });
map.mapLibreMap.addLayer({
id: 'my-layer',
type: 'circle',
source: 'my-data',
paint: { 'circle-radius': 6, 'circle-color': '#007cbf' },
});
}
},
});
Updating UI based on the active style
map.addStyleChangeHandler({
onStyleChanged: () => {
const style = map.getStyle();
const isDark = typeof style === 'string'
? style.toLowerCase().includes('dark')
: style?.id?.toLowerCase().includes('dark') ?? false;
document.body.classList.toggle('dark-mode', isDark);
},
});
Async handlers
Both callbacks can be async. The SDK awaits each one before continuing: onStyleAboutToChange handlers finish before the new style is handed to MapLibre, and the promise returned by setStyle resolves only after the last onStyleChanged handler has finished.
map.addStyleChangeHandler({
onStyleAboutToChange: async () => {
await persistStateToServer(map.getStyle());
},
onStyleChanged: async () => {
await restoreStateFromServer();
},
});
Custom styles
A custom style (style: { type: 'custom', url } or { type: 'custom', json }) loads as-is:
- Exactly one of
urlorjson; passing neither throws. - Light/dark theme: read from the style's background colour once loaded, so places and routes pick legible text colours on a dark custom style too.
lightDarkTheme: 'light' | 'dark'declares the theme instead, and the SDK takes it at its word: worth doing when full-coverage imagery hides the background, or its colour misrepresents the map. Either way,map.styleLightDarkThemereports the theme in effect.- Style parts: traffic and hillshade modules work when the style already ships the matching source. The SDK cannot add a style part to a custom style, and says so if you ask it to.
Styles from Map Maker
TomTom Map Maker is the tool to edit and host your own map styles:
- Edit: start from a TomTom template, then restyle its colours, its layer groups or single layers.
- Host: TomTom serves the style from its cloud. Publishing again updates every app using it, with no redeploy.
- Reuse: the same style serves this SDK, the TomTom Maps SDKs for Android and iOS, and MapLibre GL JS apps.
const map = new TomTomMap({
mapLibre: { container: 'map' },
style: { type: 'custom', url: 'YOUR_MAP_MAKER_STYLE_URL' },
});
- Style URL: in Map Maker's Share panel, copy the Production style URL with the Style URL only option. The SDK adds the API key you configured; a
keyalready in the URL takes priority, with a console warning. - Renderer: create the style for Standard Map Display, the one suited to MapLibre. See Choose the SDK target and map display renderer.
- Style file: a downloaded style loads as
{ type: 'custom', json }. The SDK adds no key to it, so download it With API Key. A file does not update when you publish again.
See Introduction to the map style for sources and layers, then Publish and share style and Using style in the application.
Available style parts
The map style includes multiple parts that come from different data sources:
- Base Map and POIs: Core geographic features and points of interest.
- Included and visible by default with all styles.
- Controlled by BaseMapModule and POIsModule.
- Traffic Incidents: Real-time traffic incident data.
- Included in the style by default, but hidden upfront.
- Can be optionally excluded from the style for performance.
- Controlled by TrafficIncidentsModule.
- Traffic Flow: Live traffic flow information.
- Included in the style by default, but hidden upfront.
- Can be optionally excluded from the style for performance.
- Controlled by TrafficFlowModule.
- Hillshade: Terrain elevation data, for hillshade shading and 3D terrain.
- Included in the style by default, but hidden upfront.
- Can be optionally excluded from the style for performance.
- Controlled by TerrainModule.
// Common layer modules you can include or not:
include: [
'trafficIncidents', // Traffic incidents
'trafficFlow', // Traffic flow data
'hillshade' // Terrain elevation
]
Map language
const map = new TomTomMap({
mapLibre: {
container: 'map'
},
style: 'monoLight',
language: 'de-DE' // German labels
});
Set it once — here, or in the global configuration — and it holds for the life of the map. Every style arrives with local-language labels, so the SDK re-applies the language after each style load, whether or not the switch carries state over. map.setLanguage('nl-NL') changes it at runtime.
Related guides and examples
Core map setup
- Map Quickstart - Basic map creation and style configuration
- Base Map - Control fundamental map layer visibility
- About MapLibre - Understanding the underlying mapping technology
Advanced features
- Traffic Flow - Add real-time traffic data to your styles
- Traffic Incidents - Display traffic incidents with custom styling
- Terrain - Add hillshade shading and 3D terrain to your maps
Practical examples
- Reset State When Changing Style - Carry the map state across a style switch, or drop it
- Load Style Parts - Dynamic style component loading
- Map Language - Language switching and localization
- Default map - Simple style implementation
Integration and customization
- TomTom Map Maker - Edit and host your own map styles, reusable across TomTom SDKs
- Map Styling - Adjust sizes, colours and features of the loaded style
- User Interaction Events - Handle style-related user interactions
- Places - Style integration with places data
- Routes - Route visualization with different map styles