Skip to content

Geo

@ailuracode/alpine-geo

Reactive geolocation via the $store.geo store. Wraps the browser Geolocation API with one-shot requests and continuous position watching.

Install

Terminal window
pnpm add @ailuracode/alpine-geo @ailuracode/alpine-core @ailuracode/alpine-permissions alpinejs

Quick start

import Alpine from "alpinejs";
import geo from "@ailuracode/alpine-geo";
Alpine.plugin(geo);
Alpine.start();

Avoiding name collisions

If your application already owns a $store.geo or another toolkit plugin registers on that name, rename the integration surface without touching the controller:

Alpine.plugin(geoPlugin({
storeKey: "location", // → $store.location
// magicKey follows storeKey by default → $location
magicKey: "geoState", // explicit override → $geoState
}));

storeKey is the only argument most hosts need. magicKey moves independently only when both names must be freed. The exposed constants DEFAULT_GEO_STORE_KEY and DEFAULT_GEO_MAGIC_KEY keep the rename discoverable from TypeScript.

Store API

State

Property Type Description
latitude number | null Last known latitude in decimal degrees
longitude number | null Last known longitude in decimal degrees
accuracy number | null Accuracy radius in meters
altitude number | null Altitude in meters above ellipsoid
altitudeAccuracy number | null Altitude accuracy in meters
heading number | null Direction of travel in degrees
speed number | null Speed in meters per second
timestamp number | null Position timestamp (Unix ms)
error string | null Last error message
errorCode number | null Geolocation error code (1 denied, 2 unavailable, 3 timeout)
loading boolean true while a one-shot request() is pending
watching boolean true while watch() is active

Getters

Getter Type Description
hasPosition boolean true when latitude and longitude are available
isSupported boolean true when navigator.geolocation exists
isWatching boolean Alias for watching
isLoading boolean Alias for loading
hasError boolean true when error is set

Actions

Method Returns Description
request(options?) Promise<boolean> One-shot position via getCurrentPosition
watch(options?) boolean Start watchPosition; returns false if unsupported or already watching
unwatch() boolean Stop active watch; returns false if none is active
reset() boolean Clear position and error state without stopping a watch

All actions accept optional PositionOptions: enableHighAccuracy, timeout, maximumAge.

HTML examples

<button
@click="$store.geo.request({ enableHighAccuracy: true })"
:disabled="!$store.geo.isSupported || $store.geo.isLoading"
>
Use my location
</button>
<p x-show="$store.geo.hasPosition">
You are at
<span x-text="$store.geo.latitude.toFixed(4)"></span>,
<span x-text="$store.geo.longitude.toFixed(4)"></span>
<span x-text="Math.round($store.geo.accuracy)"></span> m)
</p>
<p x-show="$store.geo.hasError" x-text="$store.geo.error"></p>
<button
x-show="!$store.geo.isWatching"
@click="$store.geo.watch()"
>
Start tracking
</button>
<button
x-show="$store.geo.isWatching"
@click="$store.geo.unwatch()"
>
Stop tracking
</button>

Notes

  • Requires user permission in secure contexts (HTTPS or localhost)
  • request() and watch() share the same reactive state; a successful update clears the previous error
  • reset() clears stored coordinates but does not stop an active watch — call unwatch() first if needed
  • Read-only environment access is not exposed as a magic; use the store for shared state and actions across components

Unified permissions adapter

import { permissionsPlugin } from "@ailuracode/alpine-permissions";
import { createGeoPermissionAdapter } from "@ailuracode/alpine-geo";
Alpine.plugin(
permissionsPlugin({
adapters: [createGeoPermissionAdapter()],
})
);

Registry key: geolocation. See permissions.md.

License

MIT