Controls
The term “control” is commonly used for all sorts of buttons and information display that take place in one of the corner of the map area. The most well know are probably the [+] and [-] zoom buttons as well as the attribution information.
User interface elements that can be added to the map. The items in this section exist outside of the map’s canvas element.
Easy to add controls 
The easiest way to add the most used controls is through the Map constructor options.
To add a control in the map constructor, you must indicate the name of the control and one of these values: true to add the control or false to hide the control. You can also indicate in which position we are going to add the control: top-left, top-right, bottom-left, bottom-right.
Example
const map = new maptilersdk.Map({
container: document.getElementById("my-container-div"),
terrainControl: true,
scaleControl: true,
fullscreenControl: "top-left",
geolocateControl: false
})
These are the controls that are directly accessible in the map constructor:
navigationControl: Shows the[+],[-]zoom buttons and tilt/bearing/compass buttons. Showing on thetop-rightby default.geolocateControl: Shows a arrow-shaped locate button. When clicked, it adds a marker and center the map. If clicked again, the marker disapears (unless the map was moved since first clicked). Showing on thetop-rightby default.terrainControl: Shows a button to enable/disable the 3D terrain (does not tilt the map). Hidden by default, showing on thetop-rightif true.scaleControl: Shows a distance scale. The unit (“metric”, “imperial” or “nautical”) can be set in the config object config.unit (default: “metric”). Hidden by default, showing on thebottom-rightif true.fullscreenControl: Shows a button that toggles the map into fullscreen. Hidden by default, showing on thetop-rightif true.
Custom controls 
MapTiler SDK JS supports two flexible ways to add custom controls to your map interface, depending on the level of control and flexibility you need.
Related examples
Programmatic Controls
Programmatic controls allow developers to have more control and register custom control elements manually by calling map.addControl() and providing a control implementation. This method is ideal for applications that require dynamic logic, event-based behaviour, or a deeper integration with a framework like React.
Custom controls are instantiated using the MaptilerCustomControl class. The element that should be used can be provided either as the element itself, or as its CSS selector. Optionally, two callback functions can be provided:
onClickfunction that is called when the element is clicked, andonRenderfunction that is called every time the map renders a new state.
Both callbacks receive the active Map instance, the associated control element itself, and an event object associated with the original event (PointerEvent and MapLibreEvent respectively).
Example
const panControl = new maptilersdk.MaptilerCustomControl(
".pan-control",
(map) => map.panBy([10, 10]), // Move southeast when clicked
(map, el) => el.classList.toggle( // Change class based on current hemisphere
"northern-hemisphere", map.getCenter().lat > 0
)
);
map.addControl(panControl);
const element = document.createElement("button");
element.className = "btn btn-primary pan-nw"
element.textContent = "Pan NW";
map.addControl(
new maptilersdk.MaptilerCustomControl(
element,
(map) => map.panBy([-10, -10]) // Move northwest when clicked
),
"top-left"
);
Example: How to add a custom control programmatically
Behaviour Overview
- Upon adding, the control element is removed from its original DOM position and inserted into the map UI.
- The
onClickcallback binds an action to user interaction. - The
onRendercallback can be used for state-based updates, styling, or other custom logic. - The control is treated as a native part of the map UI but maintains its own DOM context.
- Upon removing, the control element is moved back into its original DOM position (if any) to not interfere with DOM handling of frameworks like React.
Declarative Controls
Declarative controls offer a simple way to add interactive UI elements to the map by using HTML attributes alone. Instead of instantiating controls through JavaScript, developers annotate DOM elements and allow the SDK to discover and wire them automatically.
Declarative controls are instantiated under the hood using the MaptilerExternalControl class.
Example
Add a custom control declarative way
Enabling Detection
To activate declarative control detection:
- Set the
customControlsoption totruein the map initialization configuration, to enable detection globally. - Alternatively,
customControlsmay be set to a CSS selector string, to scope the autodetection to:- Elements matching the selector directly
- Or elements whose ancestor matches the selector
const map = new maptilersdk.Map({
container: "map",
customControls: true, // or ".custom-ui"
});
Declaring a Control
To declare a control element, use the data-maptiler-control attribute:
<button data-maptiler-control="zoom-in">+</button>
The attribute’s value must be one of the predefined keywords, or an empty value. The element is automatically registered as a control and moved into the map UI. Supported values:
| Value | Description |
|---|---|
zoom-in |
zooms the map in |
zoom-out |
zooms the map out |
toggle-projection |
toggles between Mercator and Globe projections |
toggle-terrain |
turns Terrain layer on and off |
reset-view |
resets bearing, pitch, and roll to 0 (heading north, no pitch, no roll) |
reset-bearing |
resets bearing to 0 (heading north) |
reset-pitch |
resets pitch to 0 (no pitch) |
reset-roll |
resets roll to 0 (no roll) |
| empty value | registers the element as control but does not add any functionality automatically |
Warning
An Error is thrown when an unrecognized value is used.
Grouping Controls
For grouping related controls together, use the data-maptiler-control-group attribute. This approach is ideal for styling multiple buttons as a single floating UI block.
<div data-maptiler-control-group>
<button data-maptiler-control="zoom-in">+</button>
<button data-maptiler-control="zoom-out">−</button>
</div>
- The group container (
data-maptiler-control-group) is registered as a control and moved into the map UI. - It does not receive any automatic functionality.
- Functional behaviour is attached to valid descendant elements with
data-maptiler-control.
Positioning Controls
To set a specific position for a control or group, use the data-maptiler-position. The allowed values are the same as in addControl method.
<button data-maptiler-control="reset-view" data-maptiler-position="top-left">↻</button>
<div data-maptiler-control-group data-maptiler-position="bottom-right">
<button data-maptiler-control="zoom-in">+</button>
<button data-maptiler-control="zoom-out">−</button>
</div>
State Styling via CSS
To support dynamic styling based on map state (without relying on JavaScript), custom CSS variables are set directly on the map container when declarative controls are enabled. Available CSS properties:
| Property | Description | Data type |
|---|---|---|
--maptiler-center-lng |
Longitude of map center | unitless number |
--maptiler-center-lat |
Latitude of map center | unitless number |
--maptiler-zoom |
Current zoom level | unitless number |
--maptiler-bearing |
Current map bearing (rotation) | unitless number |
--maptiler-pitch |
Pitch angle | unitless number |
--maptiler-roll |
Roll angle | unitless number |
--maptiler-is-globe-projection |
true if globe view is enabled, false otherwise |
string |
--maptiler-has-terrain |
true if terrain is active, false otherwise |
string |
This enables responsive UI tweaks via pure CSS, for example:
/* transform compass icon based on bearing and pitch */
.compass-icon {
transform: rotateX(calc(var(--maptiler-pitch) * 1deg))
rotateZ(calc(var(--maptiler-bearing) * -1deg));
}
/* change projection button icon when Globe projection is on */
@container style(--maptiler-is-globe-projection: true) {
.projection-icon {
content: "globe";
}
}
MaptilerNavigationControl 
src/ui/control/globe_control.ts
A MaptilerNavigationControl control contains zoom buttons and a compass.
Behavior changes:
- When enabled, the pitch button is always present.
- The pitch button now pitches the map if it was not (and as before, unpitches the map if pitched).
- The compass icon on the pitch button has a capped “squeeziness” factor to prevent it from looking extra flat and wide when pitch is set higher than 60.
Example
const nav = new maptilersdk.MaptilerNavigationControl();
map.addControl(nav, 'top-left');
Parameters
options (Object?)
| options.showCompass
default: true
|
If true the compass button is included. |
|---|---|
| options.showZoom
default: true
|
If true the zoom-in and zoom-out buttons are included. |
| options.visualizePitch
default: false
|
If true the pitch is visualized by rotating X-axis of compass. |
Related examples
MaptilerGeolocateControl 
src/MaptilerGeolocateControl.ts
A MaptilerGeolocateControl control provides a button that uses the browser’s geolocation API to locate the user on the map.
Not all browsers support geolocation, and some users may disable the feature. Geolocation support for modern browsers including Chrome requires sites to be served over HTTPS. If geolocation support is not available, the MaptilerGeolocateControl will show as disabled.
The zoom level applied will depend on the accuracy of the geolocation provided by the device.
The MaptilerGeolocateControl has two modes. If trackUserLocation is false (default) the control acts as a button, which when pressed will set the map’s camera to target the user location. If the user moves, the map won’t update. This is most suited for the desktop. If trackUserLocation is true the control acts as a toggle button that when active the user’s location is actively monitored for changes. In this mode the MaptilerGeolocateControl has three interaction states:
- active - the map’s camera automatically updates as the user’s location changes, keeping the location dot in the center. Initial state and upon clicking the
MaptilerGeolocateControlbutton. - passive - the user’s location dot automatically updates, but the map’s camera does not. Occurs upon the user initiating a map movement.
- disabled - occurs if Geolocation is not available, disabled or denied.
These interaction states can’t be controlled programmatically, rather they are set based on user interactions.
Behavior changes:
- Now with these defaults:
enableHighAccuracy: true (uses browser location, probably GPS)maximumAge: 0 (not using any cached location)Timeout: 6000 (6 seconds)trackUserLocation: true
- When geolocate is “active”, zooming/rotating/pitching the map no longer changes the status to “background” because it does not change the center of the map. The center of the map must move of at least 1 m (world) from the active locked position in order for the status to change to “background” (note: the “background” status means the location is still refreshed but if the user moves, the map will no longer continue to be centered on them).
- The method to update the blue disc (location precision radius) has been improved as we zoom in. It is now less shaky and behave according to perspective when the camera is tilted.
Extends Evented.
Example
map.addControl(new maptilersdk.MaptilerGeolocateControl({
positionOptions: {
enableHighAccuracy: true
},
trackUserLocation: true
}), 'top-left');
Parameters
options (Object?)
| options.positionOptions
default: {enableHighAccuracy:false,timeout:6000}
|
A Geolocation API PositionOptions object. |
|---|---|
| options.fitBoundsOptions
default: {maxZoom:15}
|
A Map#fitBounds options object to use when the map is panned and zoomed to the user's location. The default is to use a maxZoom of 15 to limit how far the map will zoom in for very accurate locations. |
| options.trackUserLocation
default: false
|
If true the Geolocate Control becomes a toggle button and when active the map will receive updates to the user's location as it changes. |
| options.showAccuracyCircle
default: true
|
By default, if showUserLocation is true, a transparent circle will be drawn around the user location indicating the accuracy (95% confidence level) of the user's location. Set to false to disable. Always disabled when showUserLocation is false. |
| options.showUserLocation
default: true
|
By default a dot will be shown on the map at the user's location. Set to false to disable. |
Methods
Programmatically request and move the map to the user's location.
Returns
boolean: Returns false if called before control was added to a map, otherwise returns true.
Example
// Initialize the geolocate control.
const geolocate = new maptilersdk.GeolocateControl({
positionOptions: {
enableHighAccuracy: true
},
trackUserLocation: true
});
// Add the control to the map.
map.addControl(geolocate);
map.on('load', function() {
geolocate.trigger();
});
Events
Fired on each Geolocation API position update which returned as an error.
Properties
(PositionError): The returned PositionError object from the callback in Geolocation.getCurrentPosition() or Geolocation.watchPosition().Example
// Initialize the geolocate control.
const geolocate = new maptilersdk.GeolocateControl({
positionOptions: {
enableHighAccuracy: true
},
trackUserLocation: true
});
// Add the control to the map.
map.addControl(geolocate);
// Set an event listener that fires
// when an error event occurs.
geolocate.on('error', function() {
console.log('An error event has occurred.')
});
Fired on each Geolocation API position update which returned as success.
Properties
(Position): The returned Position object from the callback in Geolocation.getCurrentPosition() or Geolocation.watchPosition().Example
// Initialize the geolocate control.
const geolocate = new maptilersdk.GeolocateControl({
positionOptions: {
enableHighAccuracy: true
},
trackUserLocation: true
});
// Add the control to the map.
map.addControl(geolocate);
// Set an event listener that fires
// when a geolocate event occurs.
geolocate.on('geolocate', function() {
console.log('A geolocate event has occurred.')
});
Fired on each Geolocation API position update which returned as success but user position is out of map maxBounds.
Properties
(Position): The returned Position object from the callback in Geolocation.getCurrentPosition() or Geolocation.watchPosition().Example
// Initialize the geolocate control.
const geolocate = new maptilersdk.GeolocateControl({
positionOptions: {
enableHighAccuracy: true
},
trackUserLocation: true
});
// Add the control to the map.
map.addControl(geolocate);
// Set an event listener that fires
// when an outofmaxbounds event occurs.
geolocate.on('outofmaxbounds', function() {
console.log('An outofmaxbounds event has occurred.')
});
Fired when the Geolocate Control changes to the background state, which happens when a user changes the camera during an active position lock. This only applies when trackUserLocation is true. In the background state, the dot on the map will update with location updates but the camera will not.
Example
// Initialize the geolocate control.
const geolocate = new maptilersdk.GeolocateControl({
positionOptions: {
enableHighAccuracy: true
},
trackUserLocation: true
});
// Add the control to the map.
map.addControl(geolocate);
// Set an event listener that fires
// when a trackuserlocationend event occurs.
geolocate.on('trackuserlocationend', function() {
console.log('A trackuserlocationend event has occurred.')
});
Fired when the Geolocate Control changes to the active lock state, which happens either upon first obtaining a successful Geolocation API position for the user (a geolocate event will follow), or the user clicks the geolocate button when in the background state which uses the last known position to recenter the map and enter active lock state (no geolocate event will follow unless the users's location changes).
Example
// Initialize the geolocate control.
const geolocate = new maptilersdk.GeolocateControl({
positionOptions: {
enableHighAccuracy: true
},
trackUserLocation: true
});
// Add the control to the map.
map.addControl(geolocate);
// Set an event listener that fires
// when a trackuserlocationstart event occurs.
geolocate.on('trackuserlocationstart', function() {
console.log('A trackuserlocationstart event has occurred.')
});
Related examples
MaptilerTerrainControl 
The MaptilerTerrainControl shows a button to enable/disable the 3D terrain (does not tilt the map).
Example
const terrain3d = new maptilersdk.MaptilerTerrainControl();
map.addControl(terrain3d, 'top-left');
Related examples
AttributionControl
src/ui/control/attribution_control.ts
An AttributionControl control presents the map’s attribution information. By default, the attribution control is expanded (regardless of map width).
Example
const map = new maptilersdk.Map({attributionControl: false})
.addControl(new maptilersdk.AttributionControl({
compact: true
}));
Parameters
options (Object?) (default {})
| options.compact |
If
true, the attribution control will always collapse when moving the map.If
false (default), use expanded attribution control that is always visible.If
"auto" or undefined, use responsive attribution that collapses when the user moves the map on maps less than 640 pixels wide.
Attribution should not be collapsed if it can comfortably fit on the map.
compact should only be used to modify default attribution when map size makes it impossible to fit default attribution and when the automatic compact resizing for default settings are not sufficient. Always prefer "auto" to true to show the attribution uncollapsed on large maps.
|
|---|---|
| options.customAttribution | String or strings to show in addition to any other attributions. |
ScaleControl
src/ui/control/scale_control.ts
A ScaleControl control displays the ratio of a distance on the map to the corresponding distance on the ground.
Example
const scale = new maptilersdk.ScaleControl({
maxWidth: 80,
unit: 'imperial'
});
map.addControl(scale);
scale.setUnit('metric');
Parameters
options (Object?)
| options.maxWidth
default: '100'
|
The maximum length of the scale control in pixels. |
|---|---|
| options.unit
default: 'metric'
|
Unit of the distance ('imperial', 'metric' or 'nautical'). |
Methods
Set the scale's unit of the distance
Parameters
(Unit)Unit of the distance ('imperial', 'metric' or 'nautical').FullscreenControl
src/ui/control/fullscreen_control.ts
A FullscreenControl control contains a button for toggling the map in and out of fullscreen mode.
Example
map.addControl(new maptilersdk.FullscreenControl({container: document.querySelector('body')}));
Parameters
options (Object?)
| options.container | container is the compatible DOM element which should be made full screen. By default, the map container element will be made full screen. |
|---|
Related examples
MaptilerLogoControl 
A MaptilerLogoControl replaces MaplibreLogoControl.
Can be used only with paid account.
Example
const logo = new maptilersdk.MaptilerLogoControl({
logoURL: "https://api.maptiler.com/resources/logo.svg",
linkURL: "https://www.maptiler.com"
});
map.addControl(logo, 'bottom-left');
Parameters
options (Object?)
| options.logoURL
default: ""
|
Image logo URL. |
|---|---|
| options.linkURL
default: ""
|
Logo link URL |
MaptilerMinimapControl 
A MaptilerMinimapControl control. Display a overview (minimap) in a user defined corner of the map.
Parameters
options (Object?)
| options.style
|
The map's style. This must be:
|
|---|---|
| options.zoomAdjust
default: -4
|
Set the zoom difference between the parent and the minimap. If the parent is zoomed to 10 and the minimap is zoomed to 8, the zoomAdjust should be 2. |
| options.lockZoom | Set a zoom of the minimap and don't allow any future changes. |
| options.pitchAdjust
default: false
|
Adjust the pitch only if the user requests. |
| options.containerStyle | Set CSS properties of the container using object key-values. |
| options.position
default:
'bottom-left' |
Set the position of the minimap. Valid values are 'top-left', 'top-right', 'bottom-left', and 'bottom-right'.
|
| options.parentRect | Set the parentRect fill and/or line options. |
MaptilerProjectionControl 
src/ui/control/globe_control.ts
A MaptilerProjectionControl control contains a button for toggling the map projection between “mercator” and “globe”.
Example
map.addControl(new maptilersdk.MaptilerProjectionControl());
Related examples
MaptilerExternalControl 
src/controls/MaptilerExternalControl.ts
The MaptilerExternalControl allows any existing element to automatically become a map control. Used for detected controls if customControls config is turned on.
Example
const zoomInControl = new maptilersdk.MaptilerExternalControl(
".zoom-in-control",
"zoom-in"
);
Parameters
- controlElement (
HTMLElement): Element to be used as control, specified as either reference to element itself or a CSS selector to find the element in DOM -
controlType ( MaptilerExternalControlType): One of the predefined types of functionality. Allowed values:zoom-inzoom-outtoggle-projectiontoggle-terrainreset-viewreset-bearingreset-pitchreset-roll
MaptilerCustomControl 
src/controls/MaptilerCustomControl.ts
The MaptilerCustomControl allows any existing element to become a map control.
Example
const panControl = new maptilersdk.MaptilerCustomControl(
".pan-control",
(map) => map.panBy([10, 10]), // Move southeast when clicked
(map, el) => el.classList.toggle( // Change class based on current hemisphere
"northern-hemisphere", map.getCenter().lat > 0
)
);
Parameters
-
selectorOrElement ( stringHTMLElement): Element to be used as control, specified as either reference to element itself or a CSS selector to find the element in DOM - onClick (
MaptilerCustomControlCallback<PointerEvent>?): Function called when the element is clicked - onRender (
MaptilerCustomControlCallback<MapLibreEvent>?): Function called every time the underlying map renders a new state
Info
Both callbacks receive the active Map instance, the associated control element itself, and an event object associated with the original event (PointerEvent and MapLibreEvent respectively).
Related examples
IControl
Interface for interactive controls added to the map. This is a specification for implementers to model: it is not an exported method or class. This interface is the one to use to create custom controls.
Controls must implement onAdd and onRemove, and must own an element, which is often a div element. To use MapLibre GL JS’s default control styling, add the maplibregl-ctrl class to your control’s node.
Example
// Control implemented as ES6 class
class HelloWorldControl {
onAdd(map) {
this._map = map;
this._container = document.createElement('div');
this._container.className = 'maplibregl-ctrl';
this._container.textContent = 'Hello, world';
return this._container;
}
onRemove() {
this._container.parentNode.removeChild(this._container);
this._map = undefined;
}
}
// Control implemented as ES5 prototypical class
function HelloWorldControl() { }
HelloWorldControl.prototype.onAdd = function(map) {
this._map = map;
this._container = document.createElement('div');
this._container.className = 'maplibregl-ctrl';
this._container.textContent = 'Hello, world';
return this._container;
};
HelloWorldControl.prototype.onRemove = function () {
this._container.parentNode.removeChild(this._container);
this._map = undefined;
};
Methods
Optionally provide a default position for this control. If this method is implemented and Map#addControl is called without the position parameter, the value returned by getDefaultPosition will be used as the control's position.
Returns
ControlPosition: a control position, one of the values valid in addControl.
Register a control on the map and give it a chance to register event listeners and resources. This method is called by Map#addControl internally.
Parameters
Returns
HTMLElement: The control's container element. This should be created by the control and returned by onAdd without being attached to the DOM: the map will insert the control's element into the DOM as necessary.
Unregister a control on the map and give it a chance to detach event listeners and resources. This method is called by Map#removeControl internally.
Parameters
Returns
undefined: there is no required return value for this method