# location-picker > Form-ready map location picker: pan a map under a fixed pin to pick one latitude/longitude. Web component + class, keyless OpenStreetMap by default, Google and MapLibre optional. Use it when a form needs one precise point (store or sensor location, delivery pin, venue). Not for drawing shapes, several markers, or full mapping apps. - Script tag: `` defines `` and `window.LocationPicker`. - npm: `npm i location-picker`, then `import 'location-picker'` (defines the element). `location-picker/core` is the class only. - Forms: `name="loc"` submits `loc=48.85837,2.294481`; `lat-name`/`lng-name` submit separate fields; `lat-input`/`lng-input` fill existing inputs. `required` works; reset and back/forward are handled. - Value: `"lat,lng"` string, latitude first, `""` while unset. Every commit fires `input` then `change` with `detail` `{ value, lat, lng, source, zoom, address }`. Setting `el.value` is silent. Update state from `change`; never write it back from `input` (that stops a pan). - Options: `search`, `reverse-geocode`, `locate="button"`, `provider="google" api-key="…"`, `center`, `zoom`. Errors carry a `code` and a `fix`. - Providers and policies: OSM tiles need visible attribution and use your own tiles for heavy traffic; search uses Photon (fair use); Google results only on Google maps. - Phones: `presentation="auto"` (or `"field"`) shows a compact field with a "Choose on map" button; the map opens full screen and the value changes only on Confirm (Cancel changes nothing). Same names, FormData and events; `ready` resolves at the first open. Add `search locate="button"`. Use it in checkout/delivery/sign-up forms; default is inline. - To ask a person for a location with nothing to install, send `https://cyphercodes.github.io/location-picker/pick/` with `lat`, `lng`, `zoom`, `q`, `lang`, plus `redirect=` (appends `lat`, `lng`, `address` after a click) or `return=postmessage&origin=` (posts `{ type: 'location-picker:pick', lat, lng, address }`). ```html Pick a location

Picked: nothing yet

``` **Common mistakes** - **The unpinned v1 URL.** `https://unpkg.com/location-picker/dist/location-picker.min.js` (and the same path on jsDelivr) is the frozen v1 file forever: global `locationPicker`, Google Maps only, no `` element. For v3, load `https://cdn.jsdelivr.net/npm/location-picker@3` and keep the `@3`. - **Latitude first, no arrays.** Values are `"lat,lng"` strings or `{ lat, lng }` objects. Arrays are rejected because GeoJSON uses `[lng, lat]`. A swapped pair with both numbers in range (`"2.2945,48.8584"`) cannot be detected, so check the order. - **Choose Google explicitly.** Google Maps is used only with `provider="google"`, `api-key`, `map-id` or `marker="advanced"`. Otherwise the picker uses OpenStreetMap, even when `google.maps` is already loaded on the page. - **Put `required` on the picker,** never on hidden bound inputs. A hidden, empty, `required` input blocks the submit as "not focusable". - **jQuery `.serialize()` skips custom elements.** Use bound inputs (`lat-input`/`lng-input`) or `new FormData(form)`. - **`import 'location-picker'` defines the element.** `location-picker/core` is the class only and defines nothing, so importing only `core` leaves `` blank. - **Read results from `value` or `valueAsLatLng`,** not `getMarkerPosition()`. While the picker is unset, `getMarkerPosition()` returns the view centre (for example the 20,0 world view), not a chosen point. - **The `lat`/`lng` attributes are the initial value only.** Once the control is dirty (a pan, or the `el.value = ''` that `v-model` and `formControlName` write on mount), changing them is ignored with a warning. Bind `value="lat,lng"` or call `setLocation()`. - **React SSR (`hydrateRoot`: Next.js App Router, Remix):** React applies no object props (`messages`, `geocoder`, …) and no lowercase native handlers (`onaddresschange`, `onready`, `onerror`) during hydration. Set them in a ref callback (see the React hydration recipe). - **MapLibre CSS is yours to load:** `import 'maplibre-gl/dist/maplibre-gl.css'`, or set `engine-css-url`. The library never fetches MapLibre or its CSS by default. - **The stylesheet path is `location-picker/style.css`.** `location-picker/dist/location-picker.css` is not exported. You only need it with `injectStyles: false`. **Event names per framework.** The class callbacks `onChange`/`onInput`/`onAddressChange`/`onReady`/`onError` are options of the JavaScript class only. | Framework | `change` | `input` | `addresschange` | `ready` | `error` | |---|---|---|---|---|---| | Plain JS | `addEventListener('change')` | `'input'` | `'addresschange'` | `'ready'` | `'error'` | | React 19 | `onChange` | `onInput` | `onaddresschange` | `onready` | `onerror` (NOT `onError`: React's synthetic `error` never fires for this element; a type error in `jsx/react`) | | Vue 3 | `@change` | `@input` | `@addresschange` | `@ready` | `@error` | | Angular | `(change)` | `(input)` | `(addresschange)` | `(ready)` | `(error)` | | Svelte 5 | `onchange` | `oninput` | `onaddresschange` | `onready` | `onerror` | | Solid | `on:change` | `on:input` | `on:addresschange` | `on:ready` | `on:error` | | Preact | `onchange` | `oninput` | `onaddresschange` | `onready` | `onerror` | React's lowercase native handlers are attached on client render only. After `hydrateRoot`, use a ref (React hydration recipe below). **React hydration recipe.** With `hydrateRoot` (Next.js App Router, Remix), React applies neither object props (`messages`, `mapOptions`, `engine`, `geocoder`, `geolocation`, an adapter-object `provider`) nor the lowercase native handlers to custom elements. Set them in a ref callback; refs are attached on hydration. Attributes, `value` and `onChange`/`onInput` keep working. ```tsx 'use client'; import 'location-picker'; import type {} from 'location-picker/jsx/react'; import type { AddressDetail } from 'location-picker'; import { useState } from 'react'; export function AddressField() { const [address, setAddress] = useState(null); return ( <> { if (!el) return; el.messages = { locate: 'Use my position' }; const onAddress = (e: CustomEvent) => setAddress(e.detail.address); el.addEventListener('addresschange', onAddress); return () => el.removeEventListener('addresschange', onAddress); }} />

{address ?? 'No address yet'}

); } ``` Nominatim is never a default and never appears in these examples; its usage policy (https://operations.osmfoundation.org/policies/nominatim/) forbids client-side autocomplete, so do not suggest it for the search box. ## Docs - [README](https://github.com/cyphercodes/location-picker/blob/master/README.md): quick start, forms, field mode, frameworks, Google Maps, the class - [API reference](https://github.com/cyphercodes/location-picker/blob/master/docs/api.md): every export, option, property, method and event - [Forms](https://github.com/cyphercodes/location-picker/blob/master/docs/forms.md): FormData, bound inputs, Laravel/Django, validation, reset - [Frameworks](https://github.com/cyphercodes/location-picker/blob/master/docs/frameworks.md): React/Next.js, Vue/Nuxt, Angular, Svelte, Solid, Preact, Astro, htmx - [Providers and policies](https://github.com/cyphercodes/location-picker/blob/master/docs/providers.md): OSM tiles, Google Maps, MapLibre, Photon, custom geocoders - [CSP](https://github.com/cyphercodes/location-picker/blob/master/docs/csp.md): recipes per setup - [Error codes](https://github.com/cyphercodes/location-picker/blob/master/docs/errors.md): every `code` and fix - [Troubleshooting](https://github.com/cyphercodes/location-picker/blob/master/docs/troubleshooting.md): symptoms, causes, fixes - [Migration](https://github.com/cyphercodes/location-picker/blob/master/docs/migration.md): every v1 and v2 API in v3 - [No-code embed](https://github.com/cyphercodes/location-picker/blob/master/docs/embed.md): WordPress, Webflow, Squarespace, Shopify, form services ## Examples - [Live demo and lat/long finder](https://cyphercodes.github.io/location-picker/): keyless picker, copy coordinates - [Full demo](https://cyphercodes.github.io/location-picker/example/) - [Snippet generator](https://cyphercodes.github.io/location-picker/embed/): a copy-paste field for site builders - [Pick link](https://cyphercodes.github.io/location-picker/pick/): ask a person for a location by URL - [Agent Skill](https://github.com/cyphercodes/location-picker/blob/master/skills/location-picker/SKILL.md): for coding agents, shipped in the npm package ## Optional - [llms-full.txt](https://cyphercodes.github.io/location-picker/llms-full.txt): the README and all docs in one file - [AI agents and WebMCP](https://github.com/cyphercodes/location-picker/blob/master/docs/ai-agents.md): agent resources, opt-in WebMCP tools - [Compatibility](https://cyphercodes.github.io/location-picker/compat/): generated test results - [Changelog](https://github.com/cyphercodes/location-picker/blob/master/CHANGELOG.md) - [npm package](https://www.npmjs.com/package/location-picker)