All hooks / Page, device, and user

useGeolocation

305 B minified and brotliedSourceMarkdown✓ Works in all modern browsers

The device's position, watched with navigator.geolocation.watchPosition and updated as it moves. Stops watching on unmount or when disabled.

Enabling it makes the browser ask the user for permission the first time, so pass enabled: false until the user asks for location (e.g. clicks "Use my location"). On the server and during hydration it returns the initial state: loading if enabled, with no position.

Import

import { useGeolocation } from '@vincent.ri/react-tils'
// or only this hook
import { useGeolocation } from '@vincent.ri/react-tils/useGeolocation'

Usage

const [asked, setAsked] = useState(false)
const { loading, position, error } = useGeolocation({ enabled: asked })
if (!asked) return <button onClick={() => setAsked(true)}>Use my location</button>
if (loading) return <p>Locating…</p>
if (error) return <p>Could not get your location: {error.message}</p>
return <Map lat={position!.coords.latitude} lng={position!.coords.longitude} />

Live demo

No prompt until you click.

permission: unknown

When to use it

Showing the user on a map, sorting nearby results, or filling in a location after the user asks.

When not to

A rough region is enough; use IP-based location on the server, which needs no prompt. Don't enable it on page load: users deny unexpected prompts, and a denial is hard to undo. To check the permission without prompting, use usePermission('geolocation').

API

function useGeolocation(options?: GeolocationOptions): GeolocationState
ParameterDescription
optionsenabled, enableHighAccuracy, maximumAge, and timeout. All optional.

Types

export type GeolocationOptions = {
  /** Start watching. Default `true`. Pass `false` until the user asks, to avoid a prompt on page load. */
  enabled?: boolean;
  /** Ask for GPS-level accuracy. Slower and uses more battery. Default `false`. */
  enableHighAccuracy?: boolean;
  /** Accept a cached position up to this many milliseconds old. Default `0`. */
  maximumAge?: number;
  /** Give up after this many milliseconds per attempt. Default: no limit. */
  timeout?: number;
};
export type GeolocationState = {
  /** `true` while enabled and waiting for the first position or error. */
  loading: boolean;
  position: GeolocationPosition | null;
  /** `GeolocationPositionError` (denied, unavailable, timeout), or an `Error` if the browser has no geolocation. */
  error: GeolocationPositionError | Error | null;
};

Browser support

UsesChromeEdgeFirefoxSafariChrome AndroidSafari iOS
GeolocationWidely available5+12+3.5+5+18+≤3+
  • Needs a secure page (HTTPS or localhost).

First version with support, from MDN's compatibility data (web-features 3.42.0, @mdn/browser-compat-data 8.1.5).