Traffic incident details module
TrafficIncidentDetailsModule draws exactly the incidents a trafficIncidentDetails call returned, and highlights a subset of them. Use it when your app also holds the typed incidents, for popups, lists or route correlation, and decides when they render.
The module owns the incident lines and icons it draws from your fetched details, and their look, including the focus treatment below. The live incident tiles and their colours belong to the Traffic Incidents Module. This module borrows those colours, so that module’s colors.* knobs recolour it too (Borrowed looks). No other knob reaches it. See Who owns what.
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 tile incidents are hidden until shown, so by default the two don’t collide. If your app shows TrafficIncidentsModule, hide it while this module draws, or each incident renders twice.
Initialization
import { TomTomMap, TrafficIncidentDetailsModule } from '@tomtom-org/maps-sdk/map';
const map = new TomTomMap({ mapLibre: { container: 'map' } });const incidentDetailsModule = await TrafficIncidentDetailsModule.create(map);It is data-owned, so every create() returns a new, independent instance.
Rendering incidents
Pass the service result to show():
import { trafficIncidentDetails } from '@tomtom-org/maps-sdk/services';
const result = await trafficIncidentDetails({ bbox: map.getBBox() });await incidentDetailsModule.show(result);show()replaces what was shown and clears the focus.clear()removes every incident.getShown().incidentsis the collection last passed toshow(), not a viewport query.- The
shown-featuresmodule event fires on eachshow().
Focusing a subset
setFocus(ids) marks the incidents with those ids through MapLibre feature state. setFocus(null) or setFocus([]) clears the focus:
incidentDetailsModule.setFocus([result.features[0].properties.id]);incidentDetailsModule.setFocus(null);- The default highlight widens the focused incidents and paints an outline beneath them, black on a light style and white on a dark one. The highlight only adds emphasis, so the other incidents aren’t dimmed.
setFocusdoes nothing beforeshow(). A style change that keeps state keeps the focus.- Once a handler covers the module, a hovered or clicked incident gets the same highlight. Its state is the module’s event state, which
setEventStatesets from your own UI.
Customising or disabling the highlight
highlight takes an IncidentHighlightConfig. Fields you leave unset keep their defaults:
const incidentDetailsModule = await TrafficIncidentDetailsModule.create(map, { highlight: { outline: { color: '#1976d2' }, line: { widthFactor: 1.8 } },});line.widthFactormultiplies the width of the highlighted incidents,1.6by default and clamped to1–1.8.1keeps the outline without widening. A wider stripe would cover the outline at high zoom.highlight: falseturns the highlight off for focused, hovered and clicked incidents alike.setFocusstill writesfeature-state.focused, and user events still write theireventState, for your own layers to draw.- Changing
highlighton a module already showing incidents repaints the highlighted ones in place:
incidentDetailsModule.updateConfig({ highlight: { outline: { color: '#c2185b' }, line: { widthFactor: 1.2 } } });incidentDetailsModule.updateConfig({ highlight: false });Line opacity
line.opacity (0 to 1, 1 by default) fades every incident line, focused or not. The markers and the outline of
a highlighted incident stay opaque, so a highlighted incident still stands out:
const incidentDetailsModule = await TrafficIncidentDetailsModule.create(map, { line: { opacity: 0.6 } });Events
The handlers of click, hover and the other user events receive the typed TrafficIncident, with its Date and array properties intact:
incidentDetailsModule.events.on('click', (incident) => { incidentDetailsModule.setFocus([incident.properties.id]);});The handler’s third argument, allEventFeatures, holds every incident under the pointer once, however many of its layers were hit.
Visibility and layer ordering
isVisible() reports the visible setting, true by default, not whether any incident is drawn. While the module is hidden, show() updates the data without drawing it.
incidentDetailsModule.setVisible(false);incidentDetailsModule.getShown().incidents.features.length > 0; // whether there are incidents to draw
// Above every other layer (default: below the labels, 'lowestLabel')incidentDetailsModule.updateConfig({ beforeLayerConfig: 'top' });beforeLayerConfig takes one target for every layer of the module, 'top' or a key of mapStyleLayerIDs (Layer position). You can’t position parts separately.
Layer overrides
Beyond the settings above, layers (TrafficIncidentDetailsLayersConfig) takes a partial MapLibre layer for each layer the module draws. Bottom to top, they are highlightHalo, outline, innerSolid, innerChevron, innerPattern, then the incidentMarker, jamMarker and closedRoadMarker icons.
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 },});paintandlayoutmerge per property onto the module’s own, and win over the incident colours and the highlight.- A layer an entry hides through
layout.visibilitystays hidden while the module is shown. beforeLayerConfigplaces the layers, so abeforeIDis ignored.
Every setting as data
trafficIncidentDetailsKnobCatalogue lists the module’s plain-valued settings with their kind,
range and any default that holds everywhere. You can read it with no map loaded:
import { knobEntryOf, trafficIncidentDetailsKnobCatalogue } from '@tomtom-org/maps-sdk/map';
const widthFactor = knobEntryOf(trafficIncidentDetailsKnobCatalogue, 'highlight.line.widthFactor');// { id: 'highlight.line.widthFactor', kind: 'factor', description: '…', range: { min: 1, max: 1.8, step: 0.1, bounds: 'hard' }, default: 1.6 }| Id | Kind |
|---|---|
visible | toggle, true by default |
highlight.outline.color | colour, following the map’s light/dark theme if unset |
highlight.line.widthFactor | factor 1–1.8, 1.6 by default |
line.opacity | number 0–1, 1 by default |
trafficIncidentDetailsKnobIdslists the ids,TrafficIncidentDetailsKnobIdis their union, andTrafficIncidentDetailsKnobValueOf<ID>is the plain value an id takes.- It leaves out
beforeLayerConfig,layers,highlight: false(which turns the highlight off) andevents. The incident lines take the style’s incident colours, which the Traffic Incidents Module’scolors.*knobs set. - The demo above builds its panel from the catalogue. Click an incident to focus it, then turn the highlight knobs.
Limitations
The Incident Details API returns a feature list, not rendering-ready tiles, so it lacks the tags the tile pipeline adds per feature:
- There’s no road-class-aware width or offset. Every incident is a uniform stripe centred on the road.
- There’s no declutter by road importance. Every incident shows above its layer’s minimum zoom, and the icons of shorter delays from a higher one.
- There’s no secondary cause icon. Only the primary category icon renders.
For full visual fidelity, use TrafficIncidentsModule.
Where incidents share a point or stack along one road, MapLibre’s symbol collision keeps only the icon of the longest delay, and queryRenderedFeatures can’t reach the culled ones. To surface every incident at a location, read the FeatureCollection you passed to show().
API reference
TrafficIncidentDetailsModule, TrafficIncidentDetailsModuleConfig and IncidentHighlightConfig.
Related guides and examples
Related guides
- Incident details service - The query this module draws
- Traffic incidents module - The live incident tiles, and the colours this module borrows
- Traffic overview - Every way the SDK draws traffic
Related examples
- Traffic incident details - A city’s incidents clipped to its boundary, a clicked one focused
- Traffic incident focus - A city’s incidents brought forward through
layers, and the rest of the map pushed back