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

Map theme plugin

The Map Theme plugin themes a TomTomMap from wherever a look comes from: a brand's swatches, your page's CSS, a logo or a photo, a mood, an artist. It turns any of them into the ten map colours — land, water, roads, labels — which setMapColors applies to the whole base map.

What it is for

Every source comes down to a handful of colours, and one call assigns them their roles:

The look comes from Call
A brand guide, a palette, colours a user picked deriveMapColors(colors)
Your own page's CSS deriveMapColors over its custom properties
A stylesheet: a website's, a design system's tokens deriveMapColorsFromCss(cssText)
A logo, a photo, a poster deriveMapColorsFromImage(image)
A mood, an artist a coding agent or the Agent Toolkit writes the colours, then deriveMapColors

Installation

npm install @tomtom-org/maps-sdk maplibre-gl @tomtom-org/maps-sdk-plugin-map-theme

@tomtom-org/maps-sdk and culori are peer dependencies.

From colours

import { StylingModule } from '@tomtom-org/maps-sdk/map';
import { deriveMapColors } from '@tomtom-org/maps-sdk-plugin-map-theme';

const styling = await StylingModule.get(map);
const colors = deriveMapColors(['#1d3f8a', '#e63312', '#f5d000', '#111111', '#f4f1ea']);
styling.setMapColors(colors);

deriveMapColors returns all ten colours, so a UI can show what became what, and styling.set('colors.water', …) corrects one role. Applied through setMapColors, a theme is colors.* knobs: it survives setStyle and serialises with getConfig().

How colours get their roles

The assignment is deterministic; order does not matter and near-duplicates count once.

Role Gets
land The lightest low-saturation colour — the darkest one on a dark theme — toned down to a neutral
roadMajor The most colourful (highest OKLCH chroma) colour, preferring one that is not a blue or a green
water, vegetation A blue or cyan, and a green
label The colour contrasting most with land, if it reaches 4.5:1

Roles no colour fits are derived from land — roads and outlines as shades of it, water and vegetation as muted hues — so one to eight colours always give a complete palette. mode: 'auto', the default, reads light or dark off the colours; pass { mode: 'light' } or { mode: 'dark' } to force it.

Light and dark styles

setMapColors re-derives each style's own shades at that style's offsets, so a dark theme over standardLight pushes them to black. mapColorsLightDark(colors) tells a dark theme from a light one — whether auto or the source decided it — so the map can switch first:

import { mapColorsLightDark } from '@tomtom-org/maps-sdk-plugin-map-theme';

const lightDark = mapColorsLightDark(colors);
if (lightDark !== map.styleLightDarkTheme) {
    await map.setStyle(lightDark === 'dark' ? 'standardDark' : 'standardLight');
}
styling.setMapColors(colors);

From your page's CSS

A map embedded in your own app can wear the app's brand: read the page's custom properties and its theme-color, and theme from those.

const css = getComputedStyle(document.documentElement);
const brand = ['--color-primary', '--color-accent', '--color-surface', '--color-text']
    .map((name) => css.getPropertyValue(name).trim())
    .concat(document.querySelector('meta[name="theme-color"]')?.content ?? [])
    .filter(Boolean);

styling.setMapColors(deriveMapColors(brand));

Use your design system's own property names. Colours in hex, rgb(), hsl() or a CSS name are read; anything else is skipped.

From a stylesheet

A whole stylesheet works too: a website's CSS, a design system's tokens, a file a user uploads. deriveMapColorsFromCss reads the colours it paints with and assigns them roles; it takes the CSS as text, so it needs no DOM.

import { deriveMapColorsFromCss } from '@tomtom-org/maps-sdk-plugin-map-theme';

// A File from an <input type="file" accept=".css">, or CSS a server fetched
styling.setMapColors(deriveMapColorsFromCss(await fileInput.files[0].text()));

cssColors(cssText) returns the colours without assigning roles, for a UI that lets the user edit them first.

From an image

import { deriveMapColorsFromImage } from '@tomtom-org/maps-sdk-plugin-map-theme';

// A File from an <input type="file">, a Blob, an <img>, an ImageBitmap or a CORS-readable URL
styling.setMapColors(await deriveMapColorsFromImage(fileInput.files[0], { mode: 'dark' }));

The image is drawn into a 64×64 canvas; its six dominant colours (colorCount changes that) are assigned roles. A URL must be served with Access-Control-Allow-Origin; otherwise pass the File or Blob.

Without a DOM — a worker, a test, a server — decode the image yourself and pass { data, width, height } (ImagePixels, shaped like ImageData), or call dominantColors(pixels) and hand the result to deriveMapColors. Busy photos average into muted colours; pick from dominantColors by hand when that happens.

From a mood, an artist or a website you cannot read

A mood has no colours to read, and a page cannot fetch another origin's CSS (a server can, then hand it to deriveMapColorsFromCss), so these start with a model rather than a function:

Limits

API reference

deriveMapColors · mapColorsLightDark · deriveMapColorsFromCss · cssColors · deriveMapColorsFromImage · dominantColors

Related guides and examples