This is the documentation of version 0.62.3. Go to the latest version, 1.0.0-rc.5.

Map styling

The Styling Module restyles the base map, its POIs and the traffic overlays through semantic knobs: bigger labels, thicker roads, no exit numbers, orange for slow traffic. It sits between hiding whole layer groups with the Base Map Module and editing individual MapLibre layers by hand — and unlike either, it is designed to be read by machines: the whole catalogue of knobs is available as data. The playground below is built from that catalogue: one control per knob.

This guide covers the knobs themselves. The features built on them each have a guide of their own:

Guide Covers
Map colours and the accent setMapColors over the ten map colours, and the accent the modules' own drawing defaults to
Globe and sky The view knobs: globe projection, sky, horizon and the colour behind the map
Borrowed looks The parts of places, routes and fetched incidents that follow the style's own looks
Editing style layers styling.layers, for what no knob covers

Initialization

import { TomTomMap, StylingModule } from '@tomtom-org/maps-sdk/map';

const map = new TomTomMap({ mapLibre: { container: 'map' } });
const styling = await StylingModule.get(map);

The module is shared per map: a second get() returns the same instance. Pass settings to apply them right away, for instance restored from storage:

const styling = await StylingModule.get(map, { 'labels.sizeFactor': 1.2, 'buildings.3d': true });

get resolves once the style has loaded, before the map draws it. Knobs set before that first frame, whether passed to get or set right after it, land on it as if the style had shipped them, instead of fading in from the style's own look. So a map themed at startup never shows the default colours (Themed map).

Knobs

Every adjustable thing is a knob with a stable id. Set one with set, read it with get, restore the style's own value with reset:

styling.set('labels.sizeFactor', 1.3);        // every base-map label 30% bigger
styling.set('roads.widthFactor', 0.8);        // thinner roads, hierarchy kept
styling.set('roads.exitNumbers', false);      // no exit number badges
styling.set('buildings.3d', true);            // extruded buildings
styling.set('pois.minZoom', 10);              // POIs appear from zoom 10
styling.set('traffic.flow.slowColor', '#f59e0b');

styling.get('roads.widthFactor');             // 0.8
styling.reset('roads.widthFactor');           // back to the style's width
styling.reset();                              // everything back to the style as shipped

How knobs work

A knob's kind decides what it does to the loaded MapLibre style. Most write the style's layers; a few go elsewhere: the base-map group toggles through the Base Map Module, the view knobs to the map itself, and colors.accent to no layer at all, for the modules that draw their own layers to read:

styling.set · applyPreset · setMapColors · applyConfigmap.setStyle(…)StylingModule: the knobs you set, by kindBaseMapModulemap.mapColors.accentread by routes, places,geometries and rangesMapLibre mapfactorwraps the style's own expressiona style expression E becomes 1.3 × Ecolourthe colour, and every shadethe style derived from ittoggle · number · enumshows or hides layers,sets one value, picks a modebasemap.* · buildings.*roads.shields togglesview.*projection · skycolors.accentpaints no layerThe loaded style's layerspaint · layout · filters · visibilityMap viewprojection · sky · background re-applied last, after every switchwrite through
Kind Takes What it does
factor a multiplier, 1 = as the style ships multiplies the style's own expression — text-size: E becomes ["*", 1.3, E] — so zoom ramps and the road hierarchy are kept
toggle true / false shows or hides the layers it names, view.sky the sky; the basemap.*, buildings.* and roads.shields toggles go through the Base Map Module
number a value in a range replaces one value outright: the zoom POIs appear from, the light direction of the hillshade
colour any CSS colour replaces the colour, and re-derives the shades the style built from it: recolouring slow traffic recolours its darker outline by the same offset. colors.accent paints no layer: the modules read it
enum one of the knob's options picks a mode: the hillshade method, the projection

Every knob also follows the same rules:

Knobs write only the style's layers and the map's view. What the SDK draws itself — routes, places, geometries — is configured on its own module, and a few of its parts follow the knobs (The accent, Borrowed looks).

Every knob

Group Knobs Kind
Labels & symbols labels.sizeFactor, symbols.sizeFactor factor 0.5–1.5
Roads roads.widthFactor factor 0.5–1.5
roads.exitNumbers, roads.shields, roads.arrows, roads.restricted, roads.underConstruction toggle
Buildings buildings.footprints, buildings.3d toggle
POIs pois.sizeFactor factor 0.5–1.5
pois.minZoom (3–18), pois.zoomShift (−3–3) number
pois.labelColor, pois.labelOutlineColor colour
pois.microMarkers toggle
Traffic flow traffic.flow.freeColor, traffic.flow.slowColor, traffic.flow.queueingColor, traffic.flow.stationaryColor, traffic.flow.closedColor colour
traffic.flow.widthFactor factor 0.5–2
Traffic incidents traffic.incidents.minorColor, traffic.incidents.moderateColor, traffic.incidents.majorColor, traffic.incidents.closedColor colour
traffic.incidents.widthFactor factor 0.5–2
Map colours colors.land, colors.water, colors.vegetation, colors.park, colors.artificial, colors.roadMajor, colors.road, colors.roadOutline, colors.label, colors.labelOutline, and colors.accent colour
Base-map groups basemap.land, basemap.water, basemap.roads, basemap.railways, basemap.ferries, basemap.borders, basemap.natureLabels, basemap.roadLabels, basemap.houseNumbers, basemap.smallerTownLabels, basemap.stateLabels, basemap.cityLabels, basemap.allPlaceLabels, basemap.capitalLabels, basemap.countryLabels: one per base-map layer group except the two building ones and roadShields, which are the buildings.* and roads.shields knobs above toggle
Hillshade hillshade.method (standard | basic | igor | combined | multidirectional) enum
hillshade.lightDirection (0–359), hillshade.exaggeration (0–1), hillshade.maxZoom (10–22) number
hillshade.shadowColor, hillshade.highlightColor, hillshade.accentColor colour
View view.projection (mercator | globe) enum
view.sky toggle
view.skyColor, view.horizonColor, view.spaceColor colour

Two groups restyle layers another module shows. The traffic knobs show nothing until the Traffic flow or Traffic incidents module shows its layers. The hillshade knobs shape the shading once the Terrain module shows it; that guide explains why they show nothing at city zoom until two of them are set, and how hillshade.exaggeration differs from the exaggeration of the 3D surface.

The knob catalogue

stylingKnobCatalogue lists every knob as static data — id, kind, description, range or options, and which styles it works on — so it reads the same with no map loaded as with one. styling.get(id) gives the value in force on a live map.

import { stylingKnobCatalogue } from '@tomtom-org/maps-sdk/map';

for (const knob of stylingKnobCatalogue) {
    // knob.id, knob.kind ('factor' | 'number' | 'toggle' | 'color' | 'enum'), knob.description,
    // knob.range (factor and number), knob.options (enum), knob.appliesTo
    const current = styling.get(knob.id);
}

The playground at the top of this guide is exactly that: its panel is generated from the catalogue, each control showing the value get reads. Its entries carry no default, since the loaded style decides; the other catalogues of the SDK share their shape (Every setting as data).

The ids are also exported on their own: stylingKnobIds lists every knob, typed StylingKnobId, and stylingColorKnobIds (typed StylingColorKnobId) the colour ones. Other code names a map colour through them rather than hard-coding it, as the map effects plugin does to scope its bloom.

Two things are worth copying from the playground when you wire controls up. A slider or a colour picker fires input far faster than a restyle runs, so coalesce the calls into one set per animation frame (last value wins) and apply the final value on change; the readout can follow every event, since updating a label costs nothing. And if you rebuild the panel from the config-change event, skip the rebuild for changes your own controls made — set emits the event, so rebuilding mid-drag replaces the input under the pointer. Rebuild on external changes only: a reset, a setStyle, or an agent.

Presets

A preset is a named bundle of knob settings for a common intent — TomTom's cartographic opinions, in code. stylingPresetCatalogue lists them with the settings each one applies:

Preset Intent
data-viz A quiet base for your own data on top: fewer labels and markers, thinner roads, no badges
night-driving Bigger labels and shields, wider roads and traffic tubes, POIs out of the way until close up
minimal The bare map: land, water, roads and the main place names
globe Globe projection with an atmosphere
styling.applyPreset('data-viz');                   // replaces the current settings
styling.set('labels.sizeFactor', 1.1);             // then adjust
styling.applyPreset('globe', { merge: true });     // lay a preset over what is there

A preset is exactly as durable as the knobs it sets, and re-applying one on a later SDK version keeps working for as long as those knob ids do. For the visual half of the data-viz intent — dimming and desaturating what remains — see the map effects plugin's grade and tint.

Exporting the style

exportStyle() returns the map's style as currently rendered — the loaded style with every knob applied — as a MapLibre style specification. Save it, diff it, serve it yourself, or load it back as a custom style. Tile URLs carry the API key the map was created with; strip or rotate it before publishing the file.

Settings: persist, share, re-apply

getConfig() returns the overridden knobs as a plain object; applyConfig() takes one back. It serializes cleanly, so styling can live in local storage, a URL or a pull request, and re-applying it on a later SDK version keeps working for as long as the knob ids do:

localStorage.setItem('map-styling', JSON.stringify(styling.getConfig()));
// …later
styling.applyConfig(JSON.parse(localStorage.getItem('map-styling')));

styling.events.on('config-change', (settings) => save(settings));

Style changes

The style (style on the map, or setStyle) is which map document loads; knobs adjust whichever one is loaded. Settings survive map.setStyle(...): the module re-applies them once the new style has loaded, after the other modules have restored themselves, so knobs always land on top, on the new style's first frame. A clean switch (resetState: true) drops them along with the rest of the SDK state. See Map styles.

How durable is this?

Two kinds of knobs, told apart by appliesTo in the catalogue:

That is the contract: one call the SDK re-verifies on every style release, instead of a setPaintProperty block against layer ids that nobody tests again. Which style version the SDK verified against is our business, not yours — appliesTo tells you which knobs depend on it.

Interplay with other modules

The map modules split along one line: what is shown versus how the style draws it — the rule is stated once, in Who owns what. In short:

The knobs live in one module because many reach across style parts — labels.sizeFactor, or a map colour that reaches land, water, roads and labels at once — and because a control panel or an agent wants one catalogue and one settings object for the whole look.

The two sides meet in three places, each described in Who owns what: the base-map group toggles, which write through BaseMapModule so that the later call wins; the toggles inside a module's layers (pois.microMarkers, roads.arrows and the like), which can only hide what that module shows; and pois.zoomShift, which composes with the POIsModule filters.categories setting.

API reference

For complete documentation see the StylingModule API Reference.

Related guides and examples

Related guides

Related examples