Data
useGeoLocation
Browser geolocation (MDN, opens in a new tab) state.
Demo
live · imported from hookli
Nothing runs until you click — your browser may then ask for permission. Denying it is part of the demo: the hook reports it via error instead of throwing.
import { useState } from "react";
import { useGeoLocation } from "hookli";
function Coordinates() {
const { location, error } = useGeoLocation();
if (error) return <p>{error.message}</p>;
if (!location) return <p>Locating…</p>;
const { latitude, longitude } = location.coords;
return <p>{latitude.toFixed(4)}, {longitude.toFixed(4)}</p>;
}
export function Demo() {
const [asked, setAsked] = useState(false);
// The hook may prompt for permission as soon as it mounts —
// keep it unmounted until a user gesture.
if (!asked) {
return <button onClick={() => setAsked(true)}>Where am I?</button>;
}
return <Coordinates />;
}Usage
import { useState } from "react";
import { useGeoLocation } from "hookli";
function Coordinates() {
const { location, error } = useGeoLocation();
if (error) return <p>{error.message}</p>;
if (!location) return <p>Locating…</p>;
const { latitude, longitude } = location.coords;
return <p>{latitude.toFixed(4)}, {longitude.toFixed(4)}</p>;
}
export function Demo() {
const [asked, setAsked] = useState(false);
// The hook may prompt for permission as soon as it mounts —
// keep it unmounted until a user gesture.
if (!asked) {
return <button onClick={() => setAsked(true)}>Where am I?</button>;
}
return <Coordinates />;
}API
useGeoLocation(): { location: GeolocationPosition | null; error: GeolocationError | Error | null }Parameters
This hook takes no parameters.
Returns
| Name | Type | Description |
|---|---|---|
| location | GeolocationPosition | null | hookli's trimmed position type — just coords.latitude and coords.longitude. Null until the first reading arrives. |
| error | GeolocationError | Error | null | Permission denials, unsupported browsers and failed lookups all land here — read .message for display. Requesting starts on mount, so mount the hook behind a user gesture. |
GeolocationPosition
hookli's trimmed reading — only the coordinates, not the full browser GeolocationPosition.
| Name | Type | Description |
|---|---|---|
| coords.latitude | number | Latitude in decimal degrees. |
| coords.longitude | number | Longitude in decimal degrees. |
GeolocationError
Shape of a permission or lookup failure.
| Name | Type | Description |
|---|---|---|
| code | number | Numeric error code mirrored from the browser's GeolocationPositionError. |
| message | string | Human-readable reason for the failure. |
Hook
The implementation, straight from hookli. Copy it, or install the package.
import { useEffect, useState } from "react";
interface GeolocationError {
code: number;
message: string;
}
type GeolocationPosition = {
coords: { latitude: number; longitude: number };
};
interface GeolocationState {
location: GeolocationPosition | null;
error: GeolocationError | Error | null;
}
export const useGeoLocation = (): GeolocationState => {
const [location, setLocation] = useState<GeolocationPosition | null>(null);
const [error, setError] = useState<GeolocationError | Error | null>(null);
useEffect(() => {
const getLocation = async () => {
try {
const position = await getCurrentPosition();
setLocation({
coords: {
latitude: position.coords.latitude,
longitude: position.coords.longitude,
},
});
} catch (err) {
setError(err as Error);
}
};
if (navigator.geolocation) {
navigator.permissions
.query({ name: "geolocation" })
.then((result) => {
if (result.state === "granted") {
getLocation();
} else if (result.state === "prompt") {
navigator.geolocation.getCurrentPosition(
() => getLocation(),
(err) => setError(err),
);
} else {
setError(new Error("Geolocation permission denied"));
}
})
.catch((err) => setError(err));
} else {
setError(new Error("Geolocation is not supported by this browser."));
}
}, []);
return { location, error };
};
function getCurrentPosition(): Promise<globalThis.GeolocationPosition> {
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition(resolve, reject);
});
}