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

Traffic incident details module

The Traffic Incident Details Module renders incidents fetched from the trafficIncidentDetails() REST service as a developer-controlled overlay. Use this module when you need typed incident objects in your app code — for popups, list views, route correlation, or interactive focus — and want to control exactly when incidents render.

What this module owns: the incident lines and icons it draws from the details you fetched, and how they look — including the focus treatment below. The live incident tiles and their colours belong to the Traffic Incidents Module. The module borrows those colours, so that module's colors.* knobs recolour it too (Borrowed looks). No other knob reaches it. See Who owns what.

Looking for something else?

  • The default vector-tile Traffic Incidents Module is the recommended default. It auto-renders all incidents on the map, with full road-class-aware styling and declutter.
  • Use the details module when your application already fetches incidents via the REST service and you want the on-map rendering to mirror that exact set — no more, no less.

When to use the details module vs TrafficIncidentsModule

You need… Use
Live, full-coverage incidents with no fetch TrafficIncidentsModule
Typed incident objects in your app code TrafficIncidentDetailsModule
Render exactly the result of a single REST call TrafficIncidentDetailsModule
Per-feature focus / highlight a subset TrafficIncidentDetailsModule
Maximum visual fidelity (per-road-class styling, declutter) TrafficIncidentsModule

The vector-tile incidents are hidden in the default style, so the details module does not collide with them out of the box. If you've explicitly enabled TrafficIncidentsModule elsewhere in your app, hide it again before using the details module to avoid rendering the same incidents twice.

Initialization

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

const map = new TomTomMap({ mapLibre: { container: 'map' } });
const incidentDetailsModule = await TrafficIncidentDetailsModule.create(map);

Rendering incidents

Fetch incidents with the service, then pass the result to show():

import { trafficIncidentDetails } from '@tomtom-org/maps-sdk/services';

const result = await trafficIncidentDetails({
    bbox: [4.85, 52.34, 4.95, 52.40],
    timeValidityFilter: ['present'],
});
await incidentDetailsModule.show(result);

show() replaces any previously rendered snapshot. Call clear() to remove all incidents.

Focusing a subset

setFocus(ids) writes MapLibre feature-state on each rendered incident. The default highlight widens focused incidents and paints a black outline beneath them; unfocused incidents are unchanged — the highlight adds emphasis, it does not dim the other incidents. Pass null to clear focus.

incidentDetailsModule.setFocus(['incident-id-1', 'incident-id-2']);
incidentDetailsModule.setFocus(null); // clear

A hovered or clicked incident draws the same highlight once a handler covers the module, so a click handler alone highlights what the pointer is on. Its state is the module's event state, which putEventState puts from your own UI.

Customising or disabling the highlight

The default highlight is opinionated but not baked in — pass a highlight config to TrafficIncidentDetailsModule.create(map, …):

// Override individual fields (the others fall back to defaults).
const incidentDetailsModule = await TrafficIncidentDetailsModule.create(map, {
    highlight: { outlineColor: '#1976d2', widthFactor: 1.8 },
});

widthFactor multiplies the width of highlighted incidents. It defaults to 1.6 and is clamped to its catalogue range, 1–1.8: 1 keeps the outline without widening, and a wider stripe would cover the outline at high zoom.

// Disable the visual entirely, for focused, hovered and clicked incidents alike.
// setFocus() still writes `feature-state.focused`, and user events `eventState`,
// so you can drive your own styling — e.g. extra MapLibre layers reading the
// same states, or a sidebar overlay.
const incidentDetailsModule = await TrafficIncidentDetailsModule.create(map, { highlight: false });

highlight also changes on a module already showing incidents, its fields and false alike, the highlighted ones repainting in place:

incidentDetailsModule.updateConfig({ highlight: { outlineColor: '#c2185b', widthFactor: 1.2 } });
incidentDetailsModule.updateConfig({ highlight: false });

Visibility and layer ordering

isVisible() reports the visible setting, not whether any incident is drawn: a module showing nothing still returns true. Read getShown() to know whether incidents are shown. While hidden, show() updates the data without drawing it.

incidentDetailsModule.setVisible(false);
incidentDetailsModule.setVisible(true);
incidentDetailsModule.isVisible(); // true
incidentDetailsModule.getShown().incidents.features.length > 0; // whether incidents are shown

// Place the incidents above all other layers (default: below labels):
incidentDetailsModule.updateConfig({ beforeLayerConfig: 'top' });

beforeLayerConfig takes a single target, 'top' or a key of mapStyleLayerIDs — the same shape every module accepts for the whole module. The module has no parts to position apart, so there is no record form.

Layer overrides

For what the settings above don't cover, layers takes a partial MapLibre layer for each layer the module draws, bottom to top: highlightHalo, outline, innerSolid, innerChevron, innerPattern, then the incidentMarker, jamMarker and closedRoadMarker icons. paint and layout merge per property onto the module's own, and what you set takes precedence over the incident colours and the highlight:

incidentDetailsModule.updateConfig({
    layers: {
        incidentMarker: { minzoom: 11 },              // the category icons from zoom 11
        jamMarker: { layout: { 'text-field': '' } },  // jam icons without their delay
        innerChevron: { layout: { visibility: 'none' } }, // no direction chevrons
    },
});

A layer an entry hides through layout.visibility stays hidden while the module is shown, and a beforeID is ignored: beforeLayerConfig places the layers.

Every setting as data

trafficIncidentDetailsKnobCatalogue lists the module's plain-valued settings with their kind, range and, where one value holds everywhere, their default, readable with no map loaded:

import { knobEntryOf, trafficIncidentDetailsKnobCatalogue } from '@tomtom-org/maps-sdk/map';

const widthFactor = knobEntryOf(trafficIncidentDetailsKnobCatalogue, 'highlight.widthFactor');
// { id: 'highlight.widthFactor', kind: 'factor', description: '…', range: { min: 1, max: 1.8, step: 0.1, bounds: 'hard' }, default: 1.6 }

Limitations

The Incident Details REST API returns a feature list, not a rendering-ready tile. Several tags that the vector-tile pipeline injects per-feature are absent from the REST response, so the module renders with reduced visual fidelity:

If you need full visual fidelity, use TrafficIncidentsModule.

Overlapping incidents: when multiple incidents share the same point or stack along the same road segment, MapLibre's symbol collision culling keeps only the highest-sort-key feature. Culled features are not reachable via queryRenderedFeatures. If you need to surface multiple incidents at one location, work directly with the FeatureCollection you passed to show().