npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@wcstack/geolocation

v1.13.0

Published

Declarative geolocation component for Web Components. Framework-agnostic Geolocation API primitive via wc-bindable-protocol.

Readme

@wcstack/geolocation

@wcstack/geolocation is a headless geolocation component for the wcstack ecosystem.

It is not a visual UI widget. It is an async primitive node that turns the device's location into reactive state — the same way @wcstack/fetch turns a network request into reactive state and @wcstack/timer turns the passage of time into reactive state.

With @wcstack/state, <wcs-geo> can be bound directly through path contracts:

  • input / command surface: high-accuracy, timeout, maximum-age, watch, manual, trigger
  • output state surface: position, latitude, longitude, accuracy, coords, timestamp, watching, loading, error, permission

This means location-aware work can be expressed declaratively in HTML, without writing navigator.geolocation.getCurrentPosition(), watchPosition(), clearWatch(), or teardown glue in your UI layer.

@wcstack/geolocation follows the CSBC (Core / Shell / Binding Contract) architecture:

  • Core (GeolocationCore) handles acquisition, the one-shot / watch phases, position normalization, error handling, and live permission tracking
  • Shell (<wcs-geo>) connects that state to DOM attributes, lifecycle, and declarative commands
  • Binding Contract (static wcBindable) declares observable properties, writable inputs, and callable commands

Why this exists

Geolocation is, like fetch, an asynchronous source of values — but it also has a permission gate and a continuous-watch mode. Imperatively it requires callback wiring, permission queries, and cleanup on disconnect.

@wcstack/geolocation moves that logic into a reusable component and exposes the result as bindable state. A location fix becomes a state transition, not imperative callback wiring. It is a read-only sensor: the element only produces values for the state (element → state), with no "send" path back.

Secure context required. The Geolocation API only works in a secure context (HTTPS, or localhost). Over plain HTTP on a non-localhost origin acquisition fails and <wcs-geo> surfaces an error. The exact code is browser-dependent: only when navigator.geolocation itself is absent does <wcs-geo> report POSITION_UNAVAILABLE (code 2); most browsers keep navigator.geolocation present and reject the request, so the error usually arrives as PERMISSION_DENIED (code 1). Bind error and handle the failure rather than switching on a single code.

Install

npm install @wcstack/geolocation

Quick Start

1. One-shot fix on connect (default)

When <wcs-geo> is connected to the DOM, it requests a single position fix and publishes the result.

<script type="module" src="https://esm.run/@wcstack/state/auto"></script>
<script type="module" src="https://esm.run/@wcstack/geolocation/auto"></script>

<wcs-state>
  <script type="module">
    export default {
      lat: null,
      lng: null,
      get label() {
        return this.lat == null ? "Locating…" : `${this.lat}, ${this.lng}`;
      }
    };
  </script>
</wcs-state>

<wcs-geo data-wcs="latitude: lat; longitude: lng"></wcs-geo>

<p data-wcs="textContent: label"></p>

2. Continuous watch

Add the watch attribute to stream fixes via watchPosition until the element is disconnected.

<wcs-geo watch data-wcs="latitude: lat; longitude: lng; watching: isTracking"></wcs-geo>

3. High accuracy / options

<wcs-geo high-accuracy timeout="10000" maximum-age="0"
  data-wcs="coords: position; error: geoError"></wcs-geo>

4. Manual acquisition on demand

manual skips the auto fix on connect. Trigger acquisition imperatively, via a DOM click, or from state.

<wcs-geo id="loc" manual data-wcs="latitude: lat; longitude: lng"></wcs-geo>

<!-- Optional DOM triggering: click requests a one-shot fix -->
<button data-geotarget="loc">Locate me</button>

A data-geotarget click always requests a single fix via getCurrentPosition(), regardless of mode. Pointing it at a watch element runs a one-shot fix (briefly toggling loading) alongside the ongoing watch, rather than restarting the watch. The intended target is a manual element.

Attributes / Inputs

| Attribute | Type | Default | Description | | --------------- | ------- | ---------- | ----------------------------------------------------------------------- | | high-accuracy | boolean | false | Request the best possible results (enableHighAccuracy). | | timeout | number | Infinity | Max ms to wait for a fix. Invalid values fall back to Infinity. | | maximum-age | number | 0 | Max age (ms) of an acceptable cached fix. Invalid values fall back to 0. | | watch | boolean | false | Continuously watch the position on connect instead of a single fix. | | manual | boolean | false | Do not auto-acquire on connect; acquire via command / trigger. |

Observable Properties (outputs)

| Property | Event | Description | | ------------ | ------------------------------ | --------------------------------------------------------------------- | | position | wcs-geo:position | Normalized snapshot { latitude, longitude, accuracy, altitude, altitudeAccuracy, heading, speed, timestamp, coords }. | | latitude | wcs-geo:position | Latitude of the latest fix. | | longitude | wcs-geo:position | Longitude of the latest fix. | | accuracy | wcs-geo:position | Accuracy in meters of the latest fix. | | coords | wcs-geo:position | The coordinates sub-object of the latest fix. | | timestamp | wcs-geo:position | Acquisition timestamp of the latest fix. | | watching | wcs-geo:watching-changed | true while continuously watching, false otherwise. | | loading | wcs-geo:loading-changed | true during a one-shot getCurrentPosition request. | | error | wcs-geo:error | Normalized { code, message } (PERMISSION_DENIED=1, POSITION_UNAVAILABLE=2, TIMEOUT=3). | | permission | wcs-geo:permission-changed | "prompt" / "granted" / "denied" / "unsupported", tracked live via the Permissions API. |

Commands

| Command | Description | | ------------------- | ----------------------------------------------------------------- | | getCurrentPosition| Acquire a single fix (async; never rejects — failures go to error). | | watchPosition | Begin continuously watching (no-op if already watching). | | clearWatch | Stop watching; watching becomes false. |

State-driven invocation uses the command-token protocol:

<wcs-geo manual data-wcs="command.getCurrentPosition: $command.locate"></wcs-geo>

Notes & limitations

  • Attributes are read at connect time, not observed. <wcs-geo> does not implement observedAttributes / attributeChangedCallback. Option attributes (high-accuracy, timeout, maximum-age, watch, manual) are read when the element connects and each time a command runs — changing them imperatively after connect does not by itself re-acquire or re-watch. To apply new options, call getCurrentPosition() / clearWatch() + watchPosition() again, or re-connect the element.
  • Reconnect re-acquires. Removing and re-inserting the element runs connectedCallback again, so a default-mode element fetches a fresh fix and a watch element restarts watching (matching how it tears watching down on disconnect).
  • SSR (@wcstack/server). The default one-shot mode declares static hasConnectedCallbackPromise = true and exposes connectedCallbackPromise, so the server renderer waits for the connect-time fix before snapshotting. (watch / manual modes have no connect-time fix to await.)
  • timeout / maximum-age parsing. Values are parsed strictly: a non-numeric ("10px"), non-finite, or negative value falls back to the default (Infinity / 0). Only a clean non-negative number is accepted.
  • Silent failure handling (zero-log). Consistent with the rest of wcstack's zero-dependency, minimal philosophy, <wcs-geo> never logs or throws for runtime failures. A failed permission query (e.g. a browser that rejects the geolocation permission name, or has no Permissions API) silently falls back to permission = "unsupported". Acquisition failures (PERMISSION_DENIED / POSITION_UNAVAILABLE / TIMEOUT, including a missing Geolocation API) are surfaced only through the error property / wcs-geo:error event — getCurrentPosition() resolves and never rejects. Bind error (and permission) to observe and react to these conditions.

Headless usage (GeolocationCore)

The Core has no DOM dependency and can be used directly with bind() from @wc-bindable/core:

import { GeolocationCore } from "@wcstack/geolocation";

const geo = new GeolocationCore();
geo.addEventListener("wcs-geo:position", (e) => {
  console.log((e as CustomEvent).detail); // { latitude, longitude, accuracy, ... }
});

await geo.getCurrentPosition({ enableHighAccuracy: true });
// or, for continuous updates:
geo.watch();
// ...later
geo.clearWatch();

License

MIT