Building Plugins
Plugins extend the InteractiveMap with custom buttons, panels, controls, and behaviours. This guide introduces the plugin system and links to the detailed reference documentation.
Overview
A plugin is a module that registers UI elements and logic with the map. Plugins can:
- Add buttons to the toolbar with built-in styling and behaviour
- Add panels for content like search results or layer controls
- Add controls for fully custom UI elements
- Register icons for use across the application
- Expose API methods callable from outside the plugin
- Manage state with a reducer pattern
How Plugins Work
A plugin consists of two parts:
- Factory function - Exports a function that accepts configuration and returns a PluginDescriptor
- Manifest - Defines the plugin's buttons, panels, controls, and other elements
// scale-bar/index.jsexport default function createPlugin ({ units = 'metric' } = {}) { return { id: 'scaleBar', units, load: async () => { const { manifest } = await import('./manifest.js') return manifest } }}The factory pattern allows configuration to be passed when registering the plugin. All properties (except id and load) are available as pluginConfig within the plugin.
import createScaleBarPlugin from '@defra/interactive-map-plugin-scale-bar'
const interactiveMap = new InteractiveMap({ // ... other options plugins: [ createScaleBarPlugin({ units: 'imperial' }) ]})When the map initialises, it calls each plugin's load function and registers the manifest's buttons, panels, controls, and other elements.
Plugin Context
Plugin components and callbacks receive a PluginContext object providing access to:
- appConfig - Application configuration
- appState - Current app state (breakpoint, interface type, etc.)
- mapState - Current map state (zoom, center, bounds)
- mapProvider - Methods to interact with the map
- pluginConfig - Configuration passed to the factory function
- pluginState - Plugin-specific state from your reducer
- services - Core services (announcements, reverse geocoding, event bus)
Quick Example
The scale-bar plugin displays the current map scale. It accepts a units option to configure the display format.
// scale-bar/index.jsexport default function createPlugin ({ units = 'metric' } = {}) { return { id: 'scaleBar', units, load: async () => { const { manifest } = await import('./manifest.js') return manifest } }}// scale-bar/manifest.jsimport { ScaleBar } from './ScaleBar.jsx'
export const manifest = { controls: [{ id: 'scaleBar', label: 'Scale bar', mobile: { slot: 'footer-right' }, tablet: { slot: 'footer-right' }, desktop: { slot: 'footer-right' }, render: ScaleBar }]}// scale-bar/ScaleBar.jsxexport function ScaleBar ({ mapState, pluginConfig }) { const { resolution } = mapState const { units } = pluginConfig
// Calculate scale based on resolution and units const scale = calculateScale(resolution, units)
return ( <div className="scale-bar"> {scale.label} </div> )}// Usageimport createScaleBarPlugin from '@defra/interactive-map-plugin-scale-bar'
const interactiveMap = new InteractiveMap({ plugins: [ createScaleBarPlugin({ units: 'imperial' }) ]})Reference Documentation
For detailed specifications, see:
- PluginDescriptor - How to register a plugin
- PluginManifest - What a plugin can contain
- PluginContext - Context available to plugin code
- ButtonDefinition - Button configuration
- PanelDefinition - Panel configuration
- ControlDefinition - Custom control configuration
- IconDefinition - Icon registration
- Slots - UI slot system for positioning elements
Events
Plugins can subscribe to application and map events via the eventBus service. See the Events section in the API reference for available events.
const { eventBus, events } = context.services
eventBus.on(events.APP_PANEL_OPENED, ({ panelId }) => { console.log('Panel opened:', panelId)})