8
Hooks

useGeolocation

A hook for accessing and watching browser geolocation with permission management and error handling.

useGeolocation

The useGeolocation hook provides a convenient way to access the browser’s Geolocation API. It handles permission management, position watching, and error states, supporting both one-time location requests and continuous tracking.

Geolocation
Supported

This is a simulation for preview purposes. In a real app, the permission is controlled by the browser.

No location data available

Click "Get Current Location" to get started

This is a simulation. In a real app, actual location data would be used.

Installation

Install the useGeolocation hook using:

npx axionjs-ui add hook use-geolocation

File Structure

use-geolocation.ts

Parameters

PropTypeDefault
options
GeolocationOptions
{}

Return Value

PropTypeDefault
isSupported
boolean
-
position
GeolocationPosition | null
-
error
GeolocationPositionError | null
-
isLoading
boolean
-
permissionState
PermissionState | null
-
getPosition
() => void
-
stopWatching
() => void
-
checkPermission
() => Promise<PermissionState | null>
-

Examples

Location Tracker

A location tracker application that continuously monitors position and calculates distance.

Location Tracker
Inactive

Distance

0 m

Time

0s

Click "Start Tracking" to begin tracking your location

Simulated data for demonstration purposes

Weather by Location

import { useEffect, useState } from "react";
import { useGeolocation } from "@/hooks/use-geolocation";
 
function WeatherByLocation() {
  const [weather, setWeather] = useState(null);
  const [loading, setLoading] = useState(false);
  
  const {
    position,
    error,
    isLoading: locationLoading,
    getPosition,
  } = useGeolocation({
    autoRequest: true,
    enableHighAccuracy: false,
  });
  
  useEffect(() => {
    const fetchWeather = async () => {
      if (!position) return;
      
      setLoading(true);
      try {
        const response = await fetch(
          `https://api.openweathermap.org/data/2.5/weather?lat=${position.latitude}&lon=${position.longitude}&units=metric&appid=YOUR_API_KEY`
        );
        
        if (!response.ok) {
          throw new Error("Failed to fetch weather data");
        }
        
        const data = await response.json();
        setWeather(data);
      } catch (err) {
        console.error("Weather fetch error:", err);
      } finally {
        setLoading(false);
      }
    };
    
    fetchWeather();
  }, [position]);
  
  if (error) {
    return (
      <div>
        <h2>Error getting location</h2>
        <p>{error.message}</p>
        <button onClick={getPosition}>Try Again</button>
      </div>
    );
  }
  
  return (
    <div>
      <h2>Weather Near You</h2>
      
      {locationLoading || loading ? (
        <p>Loading weather data...</p>
      ) : weather ? (
        <div>
          <h3>{weather.name}</h3>
          <div>
            <img 
              src={`https://openweathermap.org/img/wn/${weather.weather[0].icon}@2x.png`} 
              alt={weather.weather[0].description}
            />
            <p>{weather.weather[0].main}</p>
          </div>
          <p>Temperature: {weather.main.temp}°C</p>
          <p>Feels like: {weather.main.feels_like}°C</p>
          <p>Humidity: {weather.main.humidity}%</p>
          <p>Wind: {weather.wind.speed} m/s</p>
        </div>
      ) : (
        <p>Unable to get weather data. Make sure location access is enabled.</p>
      )}
      
      {position && (
        <div>
          <p>
            Your location: {position.latitude.toFixed(4)}, {position.longitude.toFixed(4)}
          </p>
          <button onClick={getPosition}>Refresh Location</button>
        </div>
      )}
    </div>
  );
}

Advanced Usage

Distance Calculation

Calculate the distance between two geographic coordinates using the Haversine formula:

/**
 * Calculate distance between two coordinates in meters
 */
export function getDistanceBetweenCoordinates(
  lat1: number,
  lon1: number,
  lat2: number,
  lon2: number
): number {
  const R = 6371e3; // Earth's radius in meters
  const φ1 = lat1 * Math.PI / 180;
  const φ2 = lat2 * Math.PI / 180;
  const Δφ = (lat2 - lat1) * Math.PI / 180;
  const Δλ = (lon2 - lon1) * Math.PI / 180;
 
  const a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
          Math.cos(φ1) * Math.cos(φ2) *
          Math.sin(Δλ/2) * Math.sin(Δλ/2);
  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
 
  return R * c;
}
 
function DistanceCalculator() {
  const { position } = useGeolocation();
  const destination = { latitude: 40.7128, longitude: -74.0060 }; // New York
  
  if (!position) {
    return <div>Getting your location...</div>;
  }
  
  const distance = getDistanceBetweenCoordinates(
    position.latitude,
    position.longitude,
    destination.latitude,
    destination.longitude
  );
  
  return (
    <div>
      <h2>Distance Calculator</h2>
      <p>You are {(distance / 1000).toFixed(1)} km from New York</p>
    </div>
  );
}

Geofencing

Create a simple geofencing system to detect when a user enters or leaves a defined area:

import { useEffect, useState } from "react";
import { useGeolocation } from "@/hooks/use-geolocation";
 
interface GeoFence {
  id: string;
  name: string;
  latitude: number;
  longitude: number;
  radius: number; // in meters
}
 
function GeoFencingExample() {
  const geofences: GeoFence[] = [
    { id: "home", name: "Home", latitude: 34.052235, longitude: -118.243683, radius: 100 },
    { id: "work", name: "Work", latitude: 34.043675, longitude: -118.266072, radius: 200 },
    { id: "gym", name: "Gym", latitude: 34.046490, longitude: -118.257749, radius: 50 },
  ];
  
  const [activeGeofences, setActiveGeofences] = useState<string[]>([]);
  
  const { position } = useGeolocation({
    watch: true,
    enableHighAccuracy: true,
  });
  
  useEffect(() => {
    if (!position) return;
    
    const newActiveGeofences = geofences.filter(fence => {
      const distance = getDistanceBetweenCoordinates(
        position.latitude,
        position.longitude,
        fence.latitude,
        fence.longitude
      );
      
      return distance <= fence.radius;
    }).map(fence => fence.id);
    
    // Check for entered geofences
    const enteredFences = newActiveGeofences.filter(id => !activeGeofences.includes(id));
    if (enteredFences.length > 0) {
      enteredFences.forEach(id => {
        const fence = geofences.find(f => f.id === id);
        console.log(`Entered: ${fence?.name}`);
        // You could trigger notifications or other actions here
      });
    }
    
    // Check for exited geofences
    const exitedFences = activeGeofences.filter(id => !newActiveGeofences.includes(id));
    if (exitedFences.length > 0) {
      exitedFences.forEach(id => {
        const fence = geofences.find(f => f.id === id);
        console.log(`Exited: ${fence?.name}`);
        // You could trigger notifications or other actions here
      });
    }
    
    setActiveGeofences(newActiveGeofences);
  }, [position, geofences, activeGeofences]);
  
  return (
    <div>
      <h2>Geofencing</h2>
      
      <div>
        <h3>Current Position</h3>
        {position ? (
          <p>
            {position.latitude.toFixed(6)}, {position.longitude.toFixed(6)}
          </p>
        ) : (
          <p>Getting position...</p>
        )}
      </div>
      
      <div>
        <h3>Geofences</h3>
        <ul>
          {geofences.map(fence => (
            <li key={fence.id}>
              {fence.name} - 
              {activeGeofences.includes(fence.id) ? (
                <span style={{ color: "green" }}>Inside</span>
              ) : (
                <span style={{ color: "red" }}>Outside</span>
              )}
            </li>
          ))}
        </ul>
      </div>
    </div>
  );
}
 
function getDistanceBetweenCoordinates(lat1, lon1, lat2, lon2) {
  // Haversine formula implementation (same as above)
  // ...
}

Use Cases

  • Location-Based Services: Delivery tracking, ride-sharing, local search
  • Fitness Applications: Run tracking, cycling apps, hiking maps
  • Navigation: Turn-by-turn directions, trip planning
  • Social Applications: Check-ins, location sharing, nearby friends
  • Geofencing: Location-based notifications, automated actions when entering/leaving areas
  • Weather Applications: Local forecasts based on user’s position
  • Augmented Reality: Placing virtual objects in physical locations
  • Emergency Services: Sending precise location data for help

Browser Support and Limitations

The Geolocation API is supported in all modern browsers, but there are some limitations to be aware of:

  • Secure Context: Geolocation only works in secure contexts (HTTPS)
  • User Permission: Always requires explicit user permission
  • Battery Impact: Continuous watching can impact battery life
  • Indoor Accuracy: May be less accurate indoors or in urban canyons
  • Mobile vs Desktop: Mobile devices often provide more accurate GPS-based locations

Performance Considerations

  • High Accuracy Mode: Using enableHighAccuracy: true provides better position data but uses more battery and may take longer
  • Watch Frequency: In watch mode, positions might not update at a consistent rate
  • Caching: The maximumAge parameter can be increased to use cached positions
  • Batch Processing: For location tracking, consider batching position updates instead of processing each one

Accessibility

  • Provide fallbacks for users who deny location access
  • Clearly communicate why location access is needed
  • Ensure error messages are descriptive and helpful
  • Allow manual location input as an alternative

Best Practices

  • Always check isSupported before attempting to use geolocation
  • Handle permission states appropriately (prompt, granted, denied)
  • Implement proper error handling
  • Stop watching when component unmounts
  • Be transparent about how location data is used
  • Only request location when necessary
  • Provide visual feedback during location acquisition
  • Consider the privacy implications of tracking user location

On this page