Map styles
A map style is the document the map loads, with its sources and layers. This guide covers which of TomTom's built-in styles loads, its optional traffic and terrain parts, its label language, and switching styles at runtime. To adjust the loaded style, such as its label sizes, road widths, colours or a globe, see Map styling.
The demo below switches between the built-in styles:
Built-in styles
Basic styles
import { TomTomMap } from '@tomtom-org/maps-sdk/map';
const map = new TomTomMap({
mapLibre: { container: 'map' },
style: 'monoDark', // 'streetLight' when left out
});
| Style ID | Look |
|---|---|
streetLight (default), streetDark |
Full-detail map, light or dark |
streetLightDriving, streetDarkDriving |
Tuned for in-car navigation |
monoLight, monoDark |
Minimal monochrome |
streetSatellite |
Satellite imagery, with the vector roads and labels drawn over it |
Each ID is the camelCase name of the TomTom Orbis style it loads. For example, streetLightDriving loads basic_street-light-driving.
standardStyleIDs lists them all, typed StandardStyleID. Use it to fill a style picker.
The map loads only these styles. To give one your brand's look, restyle it at runtime with the Styling Foundations module and map colours. The changes survive style switches.
Dynamic style switching
await map.setStyle('streetDark');
// map.mapReady is true again; routes, places and traffic are back on the new style
setStyle returns a promise:
- It resolves once the new style has loaded and every style change handler, the SDK modules' included, has finished. Awaiting it is optional, but after it the map is safe to read and draw on again.
- It rejects if the style itself fails to load. The map then stays on the style it had, with
map.mapReadyleftfalse. A tile or source that fails to load does not fail the switch. - If you call
setStyleagain while it is in flight, only the last style is applied, and both promises resolve.
map.getStyleInput() returns the style id or object the map was last given. For the resolved MapLibre style with the knobs applied, use exportStyle.
Keeping or dropping state
By default, a style switch carries everything over. That means module data and configuration (routes, places, POI filters, traffic visibility…) and the previous style's parts (traffic, terrain). For a clean switch, pass resetState: true:
// Carry everything over (default)
map.setStyle('streetDark');
// 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('streetDark', { resetState: true });
- In a switch that carries state, nothing blinks out. What the modules show stays drawn while the new style loads, then takes on its look in place. A clean switch removes it along with the old style.
- Handlers run either way. Their
context.resetStateargument tells them which kind of switch it is (below). - The map language and the geopolitical view aren't SDK state. They are re-applied to the new style either way, and only
setLanguageandsetGeopoliticalViewchange them. - If you pass the style that is already loaded, the same lifecycle runs without reloading it. So
setStyle(currentStyle, { resetState: true })resets the SDK modules over the map you are looking at.
The demo below switches styles either way, over a map with places, a route and traffic on it:
Listening to style changes
addStyleChangeHandler reacts when a style switch triggered by map.setStyle() begins or completes. Use it to preserve custom layers, sync UI state or re-create anything tied to the current style. It returns an unsubscribe function.
:::note
This handler only fires for setStyle calls on TomTomMap, not on the initial style load. For lower-level hooks, such as the initial load or 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 handler: StyleChangeHandler = {
onStyleAboutToChange: (context) => {
// Before the switch — clean up anything tied to the current style
},
onStyleChanged: (context) => {
// After the new style has loaded — restore state, re-add layers, update UI.
// context.resetState tells you whether this is a clean switch.
},
};
const unsubscribe = map.addStyleChangeHandler(handler);
// Later, when the handler's owner is torn down:
unsubscribe();
- Both callbacks are optional.
- Handlers run one after the other, by ascending
priority(default0), then in registration order. The SDK modules restore themselves at0, so a module created after your handler restores after it. The styling knobs apply at90and raw layer edits at100. To run after all of them, give your handler apriorityabove100. - A failing handler is caught and logged, and does not stop the others.
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, with no handler to write.
A style change removes the sources and layers you add through map.mapLibreMap. 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: ({ resetState }) => {
if (savedData && !resetState) {
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.styleLightDarkTheme reports whether the style is light or dark:
map.addStyleChangeHandler({
onStyleChanged: () => {
document.body.classList.toggle('dark-mode', map.styleLightDarkTheme === 'dark');
},
});
Async handlers
Both callbacks can be async. The SDK awaits each one before continuing. onStyleAboutToChange handlers finish before the SDK hands the new style to MapLibre, and the setStyle promise resolves only after the last onStyleChanged handler has finished.
map.addStyleChangeHandler({
onStyleAboutToChange: async () => {
await persistStateToServer(map.getStyleInput());
},
onStyleChanged: async () => {
await restoreStateFromServer();
},
});
Available style parts
A standard style has optional parts, each from its own data source. The base map and POIs are always part of it, controlled by BaseMapModule and POIsModule. The others, listed in styleParts, are loaded but hidden until their module shows them:
| Style part | Data | Shown by |
|---|---|---|
trafficIncidents |
Real-time traffic incidents | TrafficIncidentsModule |
trafficFlow |
Real-time traffic flow | TrafficFlowModule |
terrain |
Elevation data, for hillshade and 3D terrain | TerrainModule |
To pick them, use include. Leave it out to load all of them, or pass [] to load none:
const map = new TomTomMap({
mapLibre: { container: 'map' },
style: { type: 'standard', id: 'streetLight', include: ['trafficFlow', 'terrain'] },
});
- If you leave a part out, its module adds it when you create the module, by reloading the style with it. So leave out what you don't need at startup.
- A switch that carries state to a style with no
includekeeps the parts of the previous style.
Map language
const map = new TomTomMap({
mapLibre: { container: 'map' },
language: 'de-DE', // German labels
});
map.setLanguage('nl-NL'); // at runtime
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. Only setLanguage changes it. The traffic incident descriptions follow it too.
Related guides and examples
Core map setup
- Map quickstart - Basic map creation and style configuration
- Map styling - Adjust sizes, colours and features of the loaded style
- About MapLibre - Understanding the underlying mapping technology
Practical examples
- Map style switcher - Every built-in style, one click apart
- Four themes per style - Four maps of Amsterdam moving together, with four colour themes for each standard style
- 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