Skip to content

Controls

This document covers the Control system in Leaflet, which provides UI widgets positioned at the corners of the map. It explains the Control base class, the positioning system, lifecycle management, and patterns for creating custom controls. For information about map interaction handlers (drag, zoom, keyboard), see Map Interaction Handlers.

Control Architecture

The Control class provides a base implementation for UI widgets that are positioned at fixed locations on the map (typically in the corners). Unlike layers, controls are not part of the geographic coordinate system but are anchored to the map container's edges.

SVG
100%

Key Distinction: Controls extend Class, not Layer. They do not participate in the layer system and are always visible regardless of zoom level or pane configuration.

Positioning System

Controls are positioned in one of four corner containers on the map. The positioning system is initialized when the map is created and provides dedicated DOM containers for each corner.

Corner Positions

Position StringLocationDefault Controls
'topleft'Upper left cornerZoom control
'topright'Upper right corner(default position if not specified)
'bottomleft'Lower left cornerScale control
'bottomright'Lower right cornerAttribution control
SVG
100%

Implementation Details: The map creates four corner containers during initialization via _initControlPos(). Each corner is a <div> element with CSS classes that handle positioning through flexbox or absolute positioning.

Control Base Class

The Control class provides core functionality for positioning and lifecycle management. All controls must implement the onAdd method and optionally onRemove.

Constructor and Options

// Default options
{
  position: 'topright'  // Initial corner position
}

The constructor accepts an options object that is merged with defaults using Util.setOptions().

Core Methods

MethodDescriptionReturns
getPosition()Returns the current position stringstring
setPosition(position)Changes the control's positionthis
getContainer()Returns the control's DOM elementHTMLElement
addTo(map)Adds the control to a mapthis
remove()Removes the control from its mapthis

Position Change Behavior: When setPosition() is called, the control is removed from its current corner (if on a map) and re-added to the new corner. This ensures proper DOM ordering and CSS application.

Control Lifecycle

Controls follow a specific lifecycle pattern when being added to or removed from a map.

SVG
100%

Lifecycle Methods

onAdd(map: LeafletMap): HTMLElement (required)

  • Must be implemented by subclasses
  • Should create and return the control's container DOM element
  • Should add event listeners to map or DOM elements as needed
  • Called when the control is added to the map

onRemove(map: LeafletMap): void (optional)

  • Should clean up event listeners and resources
  • Called when the control is removed from the map
  • Not required if the control doesn't need cleanup

Insertion Order: Controls with 'bottom' positions are inserted at the beginning of their corner container (via insertBefore), while 'top' positions are appended to the end. This ensures proper visual stacking order.

Map Integration

The map provides infrastructure for hosting controls through dedicated methods and DOM structures.

Map Methods

SVG
100%

Control Container Structure: The map creates a single control container (_controlContainer) during initialization, which holds all four corner containers (_controlCorners). This structure is created by _initControlPos() and cleaned up by _clearControlPos() when the map is destroyed.

Corner Container Creation

The _initControlPos() method creates the corner infrastructure:

  1. Creates the main control container with class 'leaflet-control-container'
  2. Creates four corner divs, each with two CSS classes for positioning:
    • Vertical: 'leaflet-top' or 'leaflet-bottom'
    • Horizontal: 'leaflet-left' or 'leaflet-right'
  3. Stores references in _controlCorners object with keys: 'topleft', 'topright', 'bottomleft', 'bottomright'

Built-in Controls

Leaflet includes several built-in control implementations that extend the Control base class:

ControlPurposeDefault Position
Control.ZoomZoom in/out buttons'topleft'
Control.AttributionCopyright and data attribution'bottomright'
Control.LayersLayer switcher for base and overlay layers'topright'
Control.ScaleScale bar showing map scale'bottomleft'

Note: The implementation files for these built-in controls are not included in the provided sources, but they all follow the same pattern of extending Control and implementing onAdd() and optionally onRemove().

Creating Custom Controls

Custom controls follow a consistent pattern based on the Control base class.

Basic Pattern

SVG
100%

Implementation Requirements

Required Method: onAdd(map)

  • Must return an HTMLElement that represents the control
  • Should create DOM elements for the control's UI
  • Should attach event listeners to the map or DOM elements
  • Receives the map instance as a parameter

Optional Method: onRemove(map)

  • Should remove event listeners added in onAdd
  • Should clean up any resources or timers
  • Receives the map instance as a parameter

Accessibility Helper: _refocusOnMap(e)

  • Available to shift focus back to the map after control interaction
  • Excludes keyboard-initiated clicks (position 0,0) to maintain focus on the control for accessibility
  • Can be used in control event handlers

Example Structure

A custom control typically follows this structure:

  1. Class Definition: Extend Control class
  2. Default Options: Set via static block with setDefaultOptions()
  3. Initialization: Optional initialize() method for constructor logic
  4. DOM Creation: onAdd() creates and returns the control's container
  5. Event Binding: Attach listeners to map events or control UI
  6. Cleanup: onRemove() removes listeners and cleans up resources

Position Option: Custom controls inherit the position option from the base class, allowing users to place them in any corner.

Control vs Layer Comparison

Understanding the differences between Controls and Layers is important for choosing the right abstraction:

AspectControlLayer
Base ClassControl extends ClassLayer extends Evented
PositioningFixed to map cornersGeographic coordinates
DOM LocationControl corners in control containerPanes (tilePane, overlayPane, etc.)
Zoom BehaviorAlways visible at same sizeMay scale or have zoom limits
Primary UseUI widgets and toolsMap data and geographic features
Integrationmap.addControl() / control.addTo()map.addLayer() / layer.addTo()
Required MethodonAdd(map): HTMLElementonAdd(map): void
AttributionN/AgetAttribution() for attribution control

Key Insight: Controls are UI elements for interacting with the map itself, while layers represent geographic data to be displayed on the map. Choose Control for tools and widgets, Layer for data visualization.

Technical Details

DOM Structure

When controls are added to the map, they create a specific DOM hierarchy:

map._container (map container)
└── map._controlContainer (class: leaflet-control-container)
    ├── map._controlCorners['topleft'] (class: leaflet-top leaflet-left)
    │   └── control._container (class: leaflet-control)
    ├── map._controlCorners['topright'] (class: leaflet-top leaflet-right)
    ├── map._controlCorners['bottomleft'] (class: leaflet-bottom leaflet-left)
    └── map._controlCorners['bottomright'] (class: leaflet-bottom leaflet-right)
        └── control._container (class: leaflet-control)

Class Assignment

Every control's container element automatically receives the CSS class 'leaflet-control', which provides default styling for controls (typically including background, border, and padding).

Automatic Cleanup

Controls automatically register for cleanup when the map fires an 'unload' event. This ensures that controls are properly removed when the map is destroyed, preventing memory leaks.