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

react-gps-guard

v2.0.0

Published

A production-quality React component and hook for handling GPS/Geolocation permissions and tracking.

Readme

react-gps-guard

A production-quality React component and hook library for seamlessly handling GPS/Geolocation permissions, prompting, and continuous tracking.

Features

  • Component & Hook APIs: Use the declarative <GPSGuard> or the useGPSGuard hook.
  • Global Context Support: Wrap your app in <GPSProvider> and use useGPS() anywhere.
  • Robust Permission Handling: Gracefully handles permissions, primer screens, denied states, and disabled GPS scenarios.
  • Fully Customizable: Provides clean default UI components while allowing you to easily swap them out.
  • Cross-Platform: Handles differences between iOS, Android, Desktop, and SSR.
  • Strongly Typed: Built with TypeScript for excellent developer experience.
  • Modern Module Support: Exports ESM and CommonJS. Supports React 18 and 19.

Installation

npm install react-gps-guard

Make sure you have react and react-dom installed.


Quick Start

Import the default CSS to get the out-of-the-box styling:

import 'react-gps-guard/styles.css';
import { GPSGuard } from 'react-gps-guard';

function App() {
  return (
    <GPSGuard onLocation={(loc) => console.log('Location:', loc)}>
      <div>
        <h1>Welcome!</h1>
        <p>You can only see this if location is enabled.</p>
      </div>
    </GPSGuard>
  );
}

Comprehensive Usage Guide

1. Basic Component Usage

The <GPSGuard> component acts as a boundary. It intercepts the rendering of its children until the user grants location permissions and a valid location is retrieved.

import { GPSGuard } from 'react-gps-guard';
import 'react-gps-guard/styles.css';

export function MapFeature() {
  return (
    <GPSGuard
      enableHighAccuracy={true}
      timeout={10000}
      enablePrimer={true}
      onLocation={(loc) => console.log('Got coordinates:', loc.latitude, loc.longitude)}
      onError={(err) => console.error('GPS Error:', err.message)}
    >
      <MyMapComponent />
    </GPSGuard>
  );
}

2. Using the Hook (useGPSGuard)

If you want complete control over the UI and rendering lifecycle, use the useGPSGuard hook directly. This hook does not block rendering, it simply returns the current state.

import { useGPSGuard } from 'react-gps-guard';

export function MyLocationComponent() {
  const { 
    location, 
    permission, 
    status, 
    error,
    requestPermission,
    retry
  } = useGPSGuard({
    enableHighAccuracy: true,
    distanceFilter: 10 // Only update if user moves 10 meters
  });

  if (status === 'checking') return <p>Checking permissions...</p>;
  
  if (status === 'priming' || permission === 'prompt') {
    return (
      <div>
        <p>We need your location to show nearby stores.</p>
        <button onClick={requestPermission}>Allow Location</button>
      </div>
    );
  }

  if (status === 'error' || permission === 'denied') {
    return (
      <div>
        <p>Location Error: {error?.message}</p>
        <button onClick={retry}>Retry</button>
      </div>
    );
  }

  return (
    <div>
      <p>Your location: {location?.latitude}, {location?.longitude}</p>
    </div>
  );
}

3. Using the Context Provider

To access the user's location from anywhere in your app without prop-drilling or showing multiple permission prompts, wrap your app in a <GPSProvider>.

Setup the Provider:

import { GPSProvider } from 'react-gps-guard';
import 'react-gps-guard/styles.css';

export function App() {
  return (
    <GPSProvider autoRetry={true}>
      <Dashboard />
    </GPSProvider>
  );
}

Consume the Context:

import { useGPS } from 'react-gps-guard';

export function Dashboard() {
  const { location, loading, requestPermission, status } = useGPS();

  if (loading) return <p>Loading...</p>;

  if (status === 'priming') {
    return <button onClick={requestPermission}>Enable Tracking</button>;
  }

  return (
    <div>
      <h2>Dashboard</h2>
      {location ? (
        <p>Tracking active! Lat: {location.latitude}</p>
      ) : (
        <p>Waiting for location...</p>
      )}
    </div>
  );
}

4. Customizing UI Components

You can override the default screens of the GPSGuard by passing React components to specific props.

import { GPSGuard } from 'react-gps-guard';

<GPSGuard
  loadingComponent={
    <div className="my-spinner">Loading GPS...</div>
  }
  permissionComponent={
    <div className="my-modal">
      <h2>Location Required</h2>
      <p>Please accept our custom permission prompt.</p>
      {/* Note: In this mode, you need to use render props to actually trigger requestPermission. See below. */}
    </div>
  }
  errorComponent={
    <div className="my-error">Oops, something went wrong.</div>
  }
>
  <MainApp />
</GPSGuard>

5. Customizing UI via Render Props

For the most flexibility inside the <GPSGuard>, use the render props which pass down the required control functions (like requestPermission and retry).

import { GPSGuard } from 'react-gps-guard';

<GPSGuard
  renderLoading={() => <div className="spinner" />}
  
  renderPermission={(requestPermission, decline) => (
    <div className="custom-primer">
      <h2>We need your location</h2>
      <button onClick={requestPermission}>Allow Access</button>
      <button onClick={decline}>No Thanks</button>
    </div>
  )}
  
  renderError={(error, retry) => (
    <div className="custom-error">
      <h2>Could not get location</h2>
      <p>{error?.message}</p>
      <button onClick={retry}>Try Again</button>
    </div>
  )}
>
  <MainApp />
</GPSGuard>

API Reference

Configuration Options (GPSOptions)

These options can be passed to <GPSGuard>, <GPSProvider>, or useGPSGuard.

| Option | Type | Default | Description | |---|---|---|---| | enableHighAccuracy | boolean | true | Request highest possible accuracy (GPS vs WiFi/Cellular). | | timeout | number | 10000 | Max time in ms allowed to retrieve the location. | | maximumAge | number | 0 | Max age in ms of a cached location. 0 means always fresh. | | distanceFilter | number | undefined | Only trigger onLocation if moved by this many meters. | | autoRetry | boolean | false | Automatically retry on certain transient errors. | | retryInterval | number | 3000 | Wait time in ms before auto-retrying. | | enablePrimer | boolean | true | Show a friendly primer component before the native browser prompt. | | showInstructions | boolean | true | Show OS-specific recovery instructions on the error screen when denied. | | stopAfterMs | number | undefined | Optional time in milliseconds to automatically stop tracking after it starts. |

Event Callbacks (GPSCallbacks)

| Callback | Signature | Description | |---|---|---| | onReady | () => void | Fires when the package is initialized and ready. | | onLocation | (location: GPSLocation) => void | Fires whenever a new location is retrieved. | | onPermissionGranted | () => void | Fires when the user grants native permission. | | onPermissionDenied | () => void | Fires when the user denies native permission. | | onPermissionPrompt | () => void | Fires right before the native browser prompt is triggered. | | onGPSDisabled | () => void | Fires when position is unavailable (often means GPS hardware is off). | | onError | (error: GPSError) => void | Fires on any error. | | onStartWatching | () => void | Fires when continuous tracking begins. | | onStopWatching | () => void | Fires when tracking ends. |

Types

GPSLocation

type GPSLocation = {
  latitude: number;
  longitude: number;
  accuracy?: number;
  altitude?: number | null;
  altitudeAccuracy?: number | null;
  heading?: number | null;
  speed?: number | null;
  timestamp?: number;
};

GPSStatus 'idle' | 'checking' | 'priming' | 'watching' | 'error'

GPSPermissionState 'prompt' | 'granted' | 'denied' | 'unsupported'

GPSError

type GPSError = {
  code: 'PERMISSION_DENIED' | 'POSITION_UNAVAILABLE' | 'TIMEOUT' | 'UNSUPPORTED' | 'UNKNOWN';
  message: string;
};

Styling

If you are using the default <GPSGuard> components, you must import the CSS:

import 'react-gps-guard/styles.css';

The styles are lightweight and scoped using the .gps-guard-* class prefix. You can easily override these classes in your own global CSS files.

For example, to change the primary button color:

.gps-guard-btn-primary {
  background-color: #ff5722 !important;
}

License

MIT

react-gps-guard