# leaflet.locatecontrol

> A useful control to geolocate the user with many options. Used by osm.org and mapbox among many others.

Latest version **0.90.1** (published 2026-08-12) · MIT license · 0 weekly downloads

## Install

```sh
npm install leaflet.locatecontrol
pnpm add leaflet.locatecontrol
yarn add leaflet.locatecontrol
bun add leaflet.locatecontrol
```

## Health

**Score 70/100 (B)** — status: active.

Positive: has types; esm support; no vulnerabilities; recently updated; high maintenance score; high quality score.

Warnings: low downloads; pre 1.0.

## Facts

| | |
|---|---|
| Version | 0.90.1 |
| Published | 2026-08-12 |
| First published | 2014-10-28 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 0 |
| Unpacked size | 190.3 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 874 |
| Author | Dominik Moritz |
| Maintainers | domoritz, kristjan.esperanto |
| Keywords | leaflet, locate, plugin |

## Links

- npm: https://www.npmjs.com/package/leaflet.locatecontrol
- Repository: https://github.com/domoritz/leaflet-locatecontrol
- Homepage: https://domoritz.github.io/leaflet-locatecontrol/
- Issues: https://github.com/domoritz/leaflet-locatecontrol/issues
- npm.io page: https://npm.io/package/leaflet.locatecontrol

## Recent versions

- 0.90.1 (latest) — 2026-08-12
- 0.90.0 — 2026-05-06
- 0.89.1 — 2026-05-02
- 0.89.0 — 2026-03-08
- 0.88.0 — 2026-02-11
- 0.87.0 — 2026-01-28
- 0.86.0 — 2026-01-11
- 0.85.1 — 2025-09-08
- 0.85.0 — 2025-09-08
- 0.84.2 — 2025-04-24
- 0.84.1 — 2025-04-01
- 0.83.1 — 2025-01-07
- 0.83.0 — 2024-12-29
- 0.82.0 — 2024-10-29
- 0.81.1 — 2024-05-24
- … 56 more at https://npm.io/package/leaflet.locatecontrol/versions

## README

# <img src="favicon.svg" alt="Leaflet.Locate logo" width="40" height="40" align="top"> Leaflet.Locate

[![npm version](https://badge.fury.io/js/leaflet.locatecontrol.svg)](https://badge.fury.io/js/leaflet.locatecontrol)
[![jsDelivr Hits](https://data.jsdelivr.com/v1/package/npm/leaflet.locatecontrol/badge?style=rounded)](https://www.jsdelivr.com/package/npm/leaflet.locatecontrol)

A useful control to geolocate the user with many options. Official [Leaflet](https://leafletjs.com/plugins.html#geolocation) and [MapBox plugin](https://www.mapbox.com/mapbox.js/example/v1.0.0/leaflet-locatecontrol/).

Tested with [Leaflet](https://leafletjs.com/) 1.9.x and 2.x and [Mapbox.js](https://docs.mapbox.com/mapbox.js/) 3.3.1 in Firefox, Chrome and Safari.

Please check for [breaking changes in the changelog](https://github.com/domoritz/leaflet-locatecontrol/blob/gh-pages/CHANGELOG.md).

## Demo

Check out the [demo page](https://domoritz.github.io/leaflet-locatecontrol/) with three different examples (Leaflet UMD, Leaflet ESM, Mapbox UMD).

## Basic Usage

### Set up

1. Get the JavaScript and CSS files
2. Include the files in your project
3. Initialize the plugin

#### Get the JavaScript and CSS files

**For production:**

The best way to get the plugin is via [npm](https://www.npmjs.org/):

```bash
npm install leaflet.locatecontrol
```

Alternatively, you can use the [JsDelivr CDN](https://www.jsdelivr.com/projects/leaflet.locatecontrol) (see instructions below) or [download the files from this repository](https://github.com/domoritz/leaflet-locatecontrol/archive/gh-pages.zip).

**For development:**

Clone the repository to work with the source code:

```bash
git clone https://github.com/domoritz/leaflet-locatecontrol
```

The source files are in `src/` and the built distribution files are in `dist/`.

#### Include the JavaScript and CSS files in your project

##### With CDN

In this example, we are loading the [files from the JsDelivr CDN](https://www.jsdelivr.com/package/npm/leaflet.locatecontrol?path=dist). In the URLs below, replace `[VERSION]` with the latest release number or remove `@[VERSION]` to always use the latest version.

```html
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet.locatecontrol@[VERSION]/dist/L.Control.Locate.min.css" />
<script src="https://cdn.jsdelivr.net/npm/leaflet.locatecontrol@[VERSION]/dist/L.Control.Locate.min.js" charset="utf-8"></script>
```

##### With `npm`

```ts
import "leaflet.locatecontrol"; // Import plugin
import "leaflet.locatecontrol/dist/L.Control.Locate.min.css"; // Import styles
import L from "leaflet"; // Import L from leaflet to start using the plugin
```

If you are using a bundler or esm, use

```ts
import { LocateControl } from "leaflet.locatecontrol";
import "leaflet.locatecontrol/dist/L.Control.Locate.min.css";
```

Then use `new LocateControl()` instead of `L.control.locate()`.

#### Add the following snippet to your map initialization

This snippet adds the control to the map. You can also pass a configuration.

```js
L.control.locate().addTo(map);
```

### Possible options

The locate control inherits options from [Leaflet Controls](https://leafletjs.com/reference.html#control).

To customize the control, pass an object with your custom options to the locate control.

```js
L.control.locate(OPTIONS).addTo(map);
```

Possible options are listed in the following table. More details are [in the code](https://github.com/domoritz/leaflet-locatecontrol/blob/gh-pages/src/L.Control.Locate.js#L118).

<!-- prettier-ignore-start -->
| Option     | Type      | Description       |  Default |
|------------|-----------|-------------------|----------|
| `position` | `string`  | Position of the control | `topleft` |
| `layer` | [`Layer`](https://leafletjs.com/reference.html#layer)  | The layer that the user's location should be drawn on. | a new layer |
| `setView` | `boolean`  or `string`  | Set the map view (zoom and pan) to the user's location as it updates. Options are `false`, `'once'`, `'always'`, `'untilPan'`, or `'untilPanOrZoom'` | `'untilPanOrZoom'` |
| `flyTo` | `boolean` | Smooth pan and zoom to the location of the marker. | `false` |
| `keepCurrentZoomLevel` | `boolean` or `Array`  | Only pan when setting the view. Set to `true` to always keep the current zoom, or provide a zoom range like `[13, 18]` to only keep the zoom when it's within that range. Outside the range, the map will zoom normally. | `false` |
| `initialZoomLevel` | `false` or `integer` | After activating the plugin by clicking on the icon, zoom to the selected zoom level, even when keepCurrentZoomLevel is true. Set to `false` to disable this feature. | `false` |
| `clickBehavior` | `object`  | What to do when the user clicks on the control. Has three options `inView`, `inViewNotFollowing` and `outOfView`. Possible values are `stop` and `setView`, or the name of a behaviour to inherit from. | `{inView: 'stop', outOfView: 'setView', inViewNotFollowing: 'inView'}` |
| `returnToPrevBounds` | `boolean`  | If set, save the map bounds just before centering to the user's location. When control is disabled, set the view back to the bounds that were saved. | `false` |
| `cacheLocation` | `boolean` | Keep a cache of the location after the user deactivates the control. If set to false, the user has to wait until the locate API returns a new location before they see where they are again. | `true` |
| `showCompass` | `boolean` | Show the compass bearing on top of the location marker | `true` |
| `compassAccuracyThreshold` | `number` or `false` | Maximum allowed iOS compass accuracy in degrees (`webkitCompassAccuracy`) for displaying the compass. `-1` (uncalibrated) is always rejected. Set to `false` to always show the compass when heading data is available. | `45` |
| `drawCircle` | `boolean`  | If set, a circle that shows the location accuracy is drawn. | `true` |
| `drawMarker` | `boolean`  | If set, the marker at the users' location is drawn. | `true` |
| `markerClass` | `class`  | The class to be used to create the marker. | `LocationMarker` |
| `compassClass` | `class`  | The class to be used to create the compass marker. | `CompassMarker` |
| `circleStyle` | [`Path options`](https://leafletjs.com/reference.html#path) | Accuracy circle style properties. | see code |
| `markerStyle` | [`Path options`](https://leafletjs.com/reference.html#path) | Inner marker style properties. Only works if your marker class supports `setStyle`. | see code |
| `compassStyle` | [`Path options`](https://leafletjs.com/reference.html#path) | Triangle compass heading marker style properties. Only works if your marker class supports `setStyle`. | see code |
| `followCircleStyle` | [`Path options`](https://leafletjs.com/reference.html#path)  | Changes to the accuracy circle while following. Only need to provide changes. | `{}` |
| `followMarkerStyle` | [`Path options`](https://leafletjs.com/reference.html#path)  | Changes to the inner marker while following. Only need to provide changes. | `{}` |
| `followCompassStyle` | [`Path options`](https://leafletjs.com/reference.html#path)  | Changes to the compass marker while following. Only need to provide changes. | `{}` |
| `icon` | `string`  | The CSS class for the icon. | `leaflet-control-locate-location-arrow` |
| `iconLoading` | `string`  | The CSS class for the icon while loading. | `leaflet-control-locate-spinner` |
| `iconElementTag` | `string`  | The element to be created for icons. | `span` |
| `textElementTag` | `string`  | The element to be created for the text. | `small` |
| `circlePadding` | `array`  | Padding around the accuracy circle. | `[0, 0]` |
| `createButtonCallback` | `function`  | This callback can be used in case you would like to override button creation behavior. | see code |
| `getLocationBounds` | `function`  | This callback can be used to override the viewport tracking behavior. | see code |
| `onLocationError` | `function`  | Called on location errors. Receives the error and the control instance. | see code |
| `metric` | `boolean` | Use metric units. | `true` |
| `onLocationOutsideMapBounds` | `function`  | Called when the user's location is outside the bounds set on the map. Called repeatedly when the user's location changes. | see code |
| `showPopup` | `boolean`  | Display a pop-up when the user clicks on the inner marker. | `true` |
| `strings` | `object`  | Strings used in the control. Options are `title`, `text`, `metersUnit`, `feetUnit`, `popup` and `outsideMapBoundsMsg` | see code |
| `strings.popup` | `string` or `function`  | The string shown as popup. May contain the placeholders `{distance}`, `{unit}`, `{lat}`, `{lng}`, `{altitude}`, `{speed}` (in m/s), and `{heading}` (in degrees). If this option is specified as function, it will be executed with a single parameter `{distance, unit, lat, lng, altitude, speed, heading}` and expected to return a string. | see code |
| `locateOptions` | [`Locate options`](https://leafletjs.com/reference.html#locate-options)  | The default options passed to Leaflet's locate method. | see code |
<!-- prettier-ignore-end -->

For example, to customize the position and the title, you could write

```js
let lc = L.control
  .locate({
    position: "topright",
    strings: {
      title: "Show me where I am, yo!"
    }
  })
  .addTo(map);
```

To add text next to the location icon:

```js
let lc = L.control
  .locate({
    strings: {
      title: "Show me where I am, yo!",
      text: "Locate me"
    }
  })
  .addTo(map);
```

## Screenshot

![screenshot](https://raw.github.com/domoritz/leaflet-locatecontrol/gh-pages/screenshot.png "Screenshot showing the locate control")

## Users

Sites that use this locate control:

- [OpenStreetMap](https://www.openstreetmap.org/) on the start page
- [MapBox](https://www.mapbox.com/mapbox.js/example/v1.0.0/leaflet-locatecontrol/)
- [wheelmap.org](https://wheelmap.org/)
- [OpenMensa](https://openmensa.org/)
- [Maps Marker Pro](https://www.mapsmarker.com) (WordPress plugin)
- [Bikemap](https://jackdougherty.github.io/bikemapcode/)
- [MyRoutes](https://myroutes.io/)
- [NearbyWiki](https://en.nearbywiki.org/)
- ...

## Advanced Usage

### Methods

You can call `start()` or `stop()` on the locate control object to set the location on page load for example.

```js
// create control and add to map
let lc = L.control.locate().addTo(map);

// request location update and set location
lc.start();
```

You can keep the plugin active but stop following using `lc.stopFollowing()`.

### Events

You can leverage the native Leaflet events `locationfound` and `locationerror` to handle when geolocation is successful or produces an error. You can find out more about these events in the [Leaflet documentation](https://leafletjs.com/examples/mobile/#geolocation). Note that the control's `onLocationError` callback (which shows a browser `alert()` by default) fires independently of the `locationerror` event — override it to suppress the alert.

Additionally, the locate control fires the following events on the map object:

| Event                 | Description                                                                                                     |
| --------------------- | --------------------------------------------------------------------------------------------------------------- |
| `locateactivate`      | Fired when the control is activated                                                                             |
| `locatedeactivate`    | Fired when the control is deactivated                                                                           |
| `locatelocationfound` | Fired when a location is found (includes `latlng`, `accuracy`, `bounds`, `control`, and other geolocation data) |
| `locationtimeout`     | Fired when geolocation timeouts occur in watch mode                                                             |

The `locatelocationfound` event is particularly useful when you need to react to location updates with access to the control instance. For example, to get the location once and then stop:

```js
map.on("locatelocationfound", function (e) {
  console.log("Location found:", e.latlng);
  console.log("Accuracy:", e.accuracy, "meters");
  e.control.stop(); // Stop after first location ("one-shot" behavior)
});
```

The `locationtimeout` event is useful when geolocation timeouts occur in watch mode. This is useful for providing custom feedback to users when location acquisition takes longer than expected:

```js
map.on("locationtimeout", function (e) {
  console.log("Location timeout count:", e.count);
  // Provide custom feedback or retry logic
});
```

Note: When `watch: true` (the default), timeout errors don't stop the location tracking - the browser will automatically retry. After 3 consecutive timeouts, the control displays a visual indicator (orange spinner) to inform users that location acquisition is taking longer than usual.

### Extending

To customize the behavior of the plugin, use L.extend to override `start`, `stop`, `_drawMarker` and/or `_removeMarker`. Please be aware that functions may change and customizations become incompatible.

```js
L.Control.MyLocate = L.Control.Locate.extend({
  _drawMarker: function () {
    // override to customize the marker
  }
});

let lc = new L.Control.MyLocate();
```

### FAQ

#### How do I set the maximum zoom level?

Set the `maxZoom` in `locateOptions` (only applies when `keepCurrentZoomLevel` is `false` or when the current zoom is outside a specified range).

```js
map.addControl(
  L.control.locate({
    locateOptions: {
      maxZoom: 10
    }
  })
);
```

You can also use `keepCurrentZoomLevel: [13, 18]` to only keep zoom when it's between levels 13-18, but zoom normally outside that range:

```js
map.addControl(
  L.control.locate({
    keepCurrentZoomLevel: [13, 18],
    locateOptions: {
      maxZoom: 16
    }
  })
);
```

#### How do I enable high accuracy?

To enable [high accuracy (GPS) mode](https://leafletjs.com/reference.html#locate-options-enablehighaccuracy), set the `enableHighAccuracy` in `locateOptions`.

```js
map.addControl(
  L.control.locate({
    locateOptions: {
      enableHighAccuracy: true
    }
  })
);
```

#### Safari does not work with Leaflet 1.7.1

This is a bug in Leaflet. Disable tap to fix it for now. See [this issue](https://github.com/Leaflet/Leaflet/issues/7255) for details.

```js
let map = new L.Map('map', {
    tap: false,
    ...
});
```

## Developers

Run the demo locally with `npm start` and then open [http://localhost:9000](http://localhost:9000).

The development server is a native Node.js script (`scripts/server.js`) that serves the project on port 9000. It does not require any external dependencies. Note that modern browsers treat `localhost` as a secure context, so HTTPS is not required for the Geolocation API to work.

To generate the minified JS and CSS files, run `npm run build`.

## Prettify and linting

Before a Pull Request please check the code style.

Run `npm run lint` to check if there are code style or linting issues.

Run `npm run lint:fix` to automatically fix style and linting issues.

## Making a release (only core developer)

1. Update `CHANGELOG.md` with the changes for the new version and commit: `git commit -am "chore: update changelog"`
2. Run `npm run bump:minor` or `npm run bump:patch` (automatically bumps the version in `package.json`, runs lint, tests, and build, then stages the `dist/` files)
3. Review what will be released: `git log $(git describe --tags --abbrev=0 HEAD^)..HEAD --oneline`
4. `git push && git push --tags` to push the new version to GitHub.
5. `npm login` (if not already logged in)
6. `npm publish` to publish the new version to npm.

### Terms

- **active**: After we called `map.locate()` and before `map.stopLocate()`. Any time, the map can fire the `locationfound` or `locationerror` events.
- **following**: Following refers to whether the map zooms and pans automatically when a new location is found.

## Thanks

To all [contributors](https://github.com/domoritz/leaflet-locatecontrol/contributors) and issue reporters.

## License

This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details.

## Attributions

SVG icons from [Font Awesome v5.15.4](https://github.com/FortAwesome/Font-Awesome/releases/tag/5.15.4): [Creative Commons Attribution 4.0](https://fontawesome.com/license/free)

---
_Source: https://npm.io/package/leaflet.locatecontrol · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
