The interact plugin provides a unified way to handle user interactions for selecting map features or placing location markers.
import createInteractPlugin from '@defra/interactive-map/plugins/interact'
const interactPlugin = createInteractPlugin({
interactionModes: ['selectMarker', 'selectFeature'],
multiSelect: true,
layers: [
{ layerId: 'my-layer', idProperty: 'id' }
]
})
const interactiveMap = new InteractiveMap({
plugins: [interactPlugin]
})Options are passed to the factory function when creating the plugin.
Type: string[]
Array of mode identifiers. When set, the plugin only renders when the app is in one of these modes.
Type: string[]
Array of mode identifiers. When set, the plugin does not render when the app is in one of these modes.
Type: Array<'selectMarker' | 'selectFeature' | 'placeMarker'>
Default: ['selectMarker']
Controls which interactions are active when the user clicks the map. Values can be combined freely — the plugin always processes them in a fixed priority order: marker selection → feature selection → place marker.
'selectMarker'— clicking a placed marker toggles its selection state'selectFeature'— clicking the map attempts to match a feature fromlayers'placeMarker'— if no feature is matched (orselectFeatureis not active), places a location marker at the clicked coordinates
Note
On touch and keyboard, a crosshair and "Select" action button are shown when interact is enabled. For touch users, this applies when 'placeMarker' or 'selectFeature' is included — modes where a precise point on the map needs to be chosen. When 'selectMarker' is the only active mode, touch users tap markers directly and the crosshair is not shown.
Common combinations:
interactionModes: ['selectMarker'] // marker selection only (default)
interactionModes: ['selectFeature'] // feature selection only
interactionModes: ['placeMarker'] // always place a marker on click
interactionModes: ['selectMarker', 'selectFeature'] // select markers or features
interactionModes: ['selectFeature', 'placeMarker'] // select features, fall back to placing a marker
interactionModes: ['selectMarker', 'selectFeature', 'placeMarker'] // all interactions activeType: Array<LayerConfig>
Default: []
Array of map layer configurations that are selectable. Each entry specifies which layer to watch and how to identify features.
layers: [
{ layerId: 'my-polygons', idProperty: 'guid' },
{ layerId: 'my-lines' }
]| Property | Type | Description |
|---|---|---|
layerId |
string |
Required. The map layer identifier to enable selection on |
idProperty |
string |
Property name used as the feature's unique identifier. If omitted, features are matched by index |
labelProperty |
string |
Property name used as the feature's display label in the keyboard-accessible listbox. Required for features to appear in keyboard navigation |
selectedStroke |
string |
Overrides the selection stroke colour for this layer. Defaults to MapStyleConfig.selectedColor |
selectedFill |
string |
Overrides the selection fill colour for this layer. Defaults to transparent |
selectedStrokeWidth |
number |
Overrides the selection stroke width for this layer. Defaults to 3 |
activeStroke |
string |
Overrides the keyboard cursor ring colour for this layer. Defaults to MapStyleConfig.activeColor |
What to use as layerId depends on how your data is added to the map — these are the layers the plugin will enable for feature selection:
- Map provider directly — use the layer IDs defined in your style or added via your map provider's layer API
- Datasets plugin — use the dataset ID, or the sublayer ID for datasets with sublayers
- Draw plugin — uses generated layer IDs; inspect the map at runtime to find them (e.g.
fill-inactive.cold,stroke-inactive.coldwhen using MapLibre)
If you're unsure of the layer IDs available at runtime, set debug: true in the interact plugin options — this lets you query the map and inspect layer names in the browser console.
Type: boolean
Default: false
When true, clicking additional features adds them to the selection rather than replacing it.
Type: boolean
Default: false
When true, clicking outside any selectable feature clears the current selection.
Type: number
Default: 10
Click detection radius in pixels applied to line features. Lines have a 1px rendered width so a buffer is required for reliable selection. Polygon and symbol/icon features use exact hit detection and are unaffected by this value.
Type: boolean
Default: true
When true, the app closes after the user clicks "Done" or "Cancel".
Type: MarkerOptions
Appearance of the location marker placed on the map. Accepts the same properties as MarkerOptions. See Symbol Config for the full property reference.
createInteractPlugin({
marker: {
symbol: 'pin',
backgroundColor: { outdoor: '#d4351c', dark: '#ff6b6b' },
foregroundColor: '#ffffff'
}
})When not set, the marker inherits from the constructor symbolDefaults cascade.
Type: number
Default: 3
Stroke width used to highlight selected features. Can be overridden per layer via layers[].selectedStrokeWidth.
Selection colours — stroke and fill colours for selected features are not configured here. Stroke colour comes from
MapStyleConfig.selectedColor(falling back to themapColorSchemescheme default), ensuring the selection colour stays consistent with the rest of the map theme. Fill defaults totransparent. Both can be overridden per layer vialayers[].selectedStrokeandlayers[].selectedFill.
Methods are called on the plugin instance after the map is ready.
Enable interaction mode. Shows action buttons and enables feature selection or marker placement. Accepts an optional options object to override any of the factory options at runtime.
| Parameter | Type | Description |
|---|---|---|
options |
Object |
Optional. Any factory options to apply for this session |
interactiveMap.on('map:ready', () => {
interactPlugin.enable()
})
// Override options at runtime
interactPlugin.enable({ multiSelect: true, interactionModes: ['selectFeature'] })Disable interaction mode. Hides action buttons and disables interactions.
interactPlugin.disable()Clear all selected features and markers, and remove the location marker.
interactPlugin.clear()Programmatically select a feature.
| Parameter | Type | Description |
|---|---|---|
featureInfo.featureId |
string |
The feature's identifier value |
featureInfo.layerId |
string |
Optional. The layer the feature belongs to |
featureInfo.idProperty |
string |
Optional. The property name used as the identifier |
interactPlugin.selectFeature({
featureId: 'abc123',
layerId: 'my-layer',
idProperty: 'id'
})Respects the current multiSelect setting — if multiSelect is false, the new feature replaces the existing selection.
Programmatically unselect a specific feature.
| Parameter | Type | Description |
|---|---|---|
featureInfo.featureId |
string |
The feature's identifier value |
featureInfo.layerId |
string |
Optional. The layer the feature belongs to |
featureInfo.idProperty |
string |
Optional. The property name used as the identifier |
interactPlugin.unselectFeature({
featureId: 'abc123'
})Programmatically select a marker. Idempotent — has no effect if the marker is already selected. In single-select mode, clears any selected features and replaces the marker selection. In multi-select mode, adds to the existing selection.
| Parameter | Type | Description |
|---|---|---|
markerId |
string |
The ID of the marker to select |
interactPlugin.selectMarker('my-marker')Programmatically unselect a specific marker. Idempotent — has no effect if the marker is not selected.
| Parameter | Type | Description |
|---|---|---|
markerId |
string |
The ID of the marker to unselect |
interactPlugin.unselectMarker('my-marker')Subscribe to events using interactiveMap.on().
Emitted when the user confirms their selection (clicks "Done").
Payload:
{
// If a location marker was placed:
coords: [lng, lat],
// If features were selected:
selectedFeatures: [...],
selectionBounds: [west, south, east, north],
// If markers were selected:
selectedMarkers: ['...']
}interactiveMap.on('interact:done', (e) => {
if (e.coords) {
console.log('Location selected:', e.coords)
}
if (e.selectedFeatures) {
console.log('Features selected:', e.selectedFeatures)
}
if (e.selectedMarkers) {
console.log('Markers selected:', e.selectedMarkers)
}
})Emitted when the user cancels the interaction (clicks "Back").
Payload: None
interactiveMap.on('interact:cancel', () => {
console.log('Interaction cancelled')
})Emitted whenever the selected features or selected markers change.
Payload:
{
selectedFeatures: [
{ featureId: '...', layerId: '...', properties: {...}, geometry: {...} }
],
selectedMarkers: ['...'], // array of selected marker IDs
selectionBounds: [west, south, east, north] | null,
contiguous: boolean // true when 2+ features are selected and all form a single contiguous group
}interactiveMap.on('interact:selectionchange', (e) => {
console.log('Selected features:', e.selectedFeatures)
console.log('Bounds:', e.selectionBounds)
})Emitted when a location marker is placed or moved.
Payload:
{
coords: [lng, lat]
}interactiveMap.on('interact:markerchange', ({ coords }) => {
console.log('Marker moved to:', coords)
})