An open-source toolkit around the Google Maps JavaScript SDK that simplifies usage for frontend teams by providing framework-agnostic utilities and optional framework-specific wrappers.
Try it out: https://demo-app-rouge-five.vercel.app/
The demo showcases all features including maps, geocoding, directions, and places functionality.
- Framework-agnostic core - Plain TypeScript functions & utilities
- Script loader - Easy Google Maps SDK loading
- Map initialization - Simple map creation with typed options
- Markers & InfoWindows - Easy marker management
- Places Autocomplete - Places API integration
- Places API (New) - Enhanced Places API with better CORS support
- Geocoding - Address β coordinates conversion
- Directions - Route planning and navigation
- Distance Matrix - Calculate distances between multiple points
- Street View - Create and manage Street View panoramas
- Web services - Typed REST clients for Places & Geocoding APIs
- Event handling - Map, marker, and Street View event utilities
@gmaps-kit/core
- Framework-agnostic core utilities@gmaps-kit/react
- React hooks and components@gmaps-kit/vue
- Vue wrapper (coming soon)@gmaps-kit/angular
- Angular wrapper (coming soon)
npm install @gmaps-kit/core
import { loadGoogleMaps } from '@gmaps-kit/core';
// Load Google Maps with your API key
await loadGoogleMaps({
apiKey: 'YOUR_API_KEY',
libraries: ['places', 'geometry'],
});
import { createMap } from '@gmaps-kit/core';
const mapInstance = createMap('map-container', {
center: { lat: 40.7128, lng: -74.006 },
zoom: 10,
});
import { addMarker, createInfoWindow, openInfoWindow } from '@gmaps-kit/core';
// Add a marker
const marker = addMarker(mapInstance.map, {
position: { lat: 40.7128, lng: -74.006 },
title: 'New York City',
});
// Create and open an InfoWindow
const infoWindow = createInfoWindow({
content: '<h3>New York City</h3><p>The Big Apple!</p>',
});
openInfoWindow(infoWindow, marker, mapInstance.map);
import { bindAutocompleteToMap } from '@gmaps-kit/core';
const input = document.getElementById('search-input') as HTMLInputElement;
const autocomplete = bindAutocompleteToMap(mapInstance, {
input,
types: ['establishment'],
});
import { geocodeAsync, reverseGeocodeAsync } from '@gmaps-kit/core';
// Address to coordinates
const results = await geocodeAsync(
'1600 Amphitheatre Parkway, Mountain View, CA'
);
console.log(results[0].location); // { lat: 37.4220656, lng: -122.0840897 }
// Coordinates to address
const address = await reverseGeocodeAsync({
lat: 37.4220656,
lng: -122.0840897,
});
console.log(address[0].address); // "1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA"
import { getDirectionsAsync, renderDirections } from '@gmaps-kit/core';
// Get directions
const directions = await getDirectionsAsync({
origin: 'New York, NY',
destination: 'Los Angeles, CA',
travelMode: 'DRIVING',
});
// Render on map
const directionsRenderer = renderDirections(mapInstance.map, directions);
import { PlacesNewClient } from '@gmaps-kit/core';
// Initialize the new Places API client
const placesNewClient = new PlacesNewClient({
apiKey: 'YOUR_API_KEY',
// No baseUrl needed - direct API calls with better CORS support!
});
// Text search with enhanced data
const textResults = await placesNewClient.textSearch({
textQuery: 'restaurants in New York',
locationBias: {
circle: {
center: { latitude: 40.7128, longitude: -74.006 },
radius: 1000,
},
},
maxResultCount: 10,
minRating: 4.0,
});
// Nearby search with better filtering
const nearbyResults = await placesNewClient.nearbySearch({
includedTypes: ['restaurant', 'cafe'],
locationRestriction: {
circle: {
center: { latitude: 40.7128, longitude: -74.006 },
radius: 1000,
},
},
maxResultCount: 10,
minRating: 4.0,
});
// Get detailed place information
const placeDetails = await placesNewClient.placeDetails({
placeId: 'ChIJN1t_tDeuEmsRUsoyG83frY4',
});
// Place autocomplete
const autocompleteResults = await placesNewClient.autocomplete({
input: 'restaurants in',
locationBias: {
circle: {
center: { latitude: 40.7128, longitude: -74.006 },
radius: 1000,
},
},
});
// Build photo URL
const photoUrl = placesNewClient.buildPhotoUrl('photos/123', {
maxWidthPx: 400,
maxHeightPx: 300,
});
Feature | Legacy API | New API (New) |
---|---|---|
CORS Support | β Requires proxy | β Direct browser requests |
Request Format | Query parameters | JSON body |
Authentication | API key in URL | API key in header |
Data Quality | Basic | Enhanced with more fields |
Error Handling | Limited | Comprehensive |
Rate Limiting | Basic | Advanced |
import { createStreetViewPanorama } from '@gmaps-kit/core';
const streetView = createStreetViewPanorama('street-view-container', {
position: { lat: 40.6892, lng: -74.0445 },
pov: { heading: 90, pitch: 0 },
zoom: 1,
});
streetView.panorama.addListener('pov_changed', () => {
console.log(streetView.panorama.getPov());
});
import { PlacesClient, GeocodingClient } from '@gmaps-kit/core';
const places = new PlacesClient({ apiKey: 'YOUR_API_KEY' });
const geocode = new GeocodingClient({ apiKey: 'YOUR_API_KEY' });
const coffeeShops = await places.textSearch({ query: 'coffee in Seattle' });
const geocodeResult = await geocode.geocode({
address: '221B Baker Street, London',
});
// Load Google Maps SDK
await loadGoogleMaps({
apiKey: string;
libraries?: string[];
language?: string;
region?: string;
version?: string;
callback?: string;
});
// Check if Google Maps is loaded
const isLoaded = isGoogleMapsLoaded();
// Wait for Google Maps to load
await waitForGoogleMaps(timeout?: number);
// Create a map
const mapInstance = createMap(container, options, eventHandlers?);
// Map controls
getMapCenter(map);
setMapCenter(map, center);
getMapZoom(map);
setMapZoom(map, zoom);
panTo(map, center, zoom?);
fitMapToMarkers(map, markers, padding?);
const streetView = createStreetViewPanorama(container, options, handlers?);
setStreetViewPosition(streetView.panorama, position);
setStreetViewPov(streetView.panorama, pov);
setStreetViewVisibility(streetView.panorama, visible);
isStreetViewVisible(streetView.panorama);
// Add marker
const marker = addMarker(map, {
position: { lat: number, lng: number };
title?: string;
label?: string;
icon?: string | Icon | Symbol;
animation?: Animation;
draggable?: boolean;
clickable?: boolean;
zIndex?: number;
});
// InfoWindow
const infoWindow = createInfoWindow({
content: string;
position?: LatLngLiteral;
maxWidth?: number;
pixelOffset?: Size;
disableAutoPan?: boolean;
});
openInfoWindow(infoWindow, marker, map);
closeInfoWindow(infoWindow);
// Create autocomplete
const autocomplete = createAutocomplete({
input: HTMLInputElement;
bounds?: LatLngBounds;
componentRestrictions?: ComponentRestrictions;
fields?: string[];
strictBounds?: boolean;
types?: string[];
});
// Bind to map
const autocomplete = bindAutocompleteToMap(mapInstance, options);
// Geocode address
const results = await geocodeAsync(address);
const firstResult = await geocodeFirst(address);
// Reverse geocode coordinates
const results = await reverseGeocodeAsync(location);
const firstResult = await reverseGeocodeFirst(location);
const places = new PlacesClient({
apiKey: 'YOUR_API_KEY',
retryConfig: { retries: 2, delayMs: 500 },
});
const restaurants = await places.textSearch({
query: 'restaurants near Portland',
type: 'restaurant',
});
if (restaurants.next_page_token) {
const more = await places.textSearchNextPage(restaurants.next_page_token);
}
const geocodeClient = new GeocodingClient({ apiKey: 'YOUR_API_KEY' });
const forward = await geocodeClient.geocode({
address: '10 Downing Street, London',
components: { country: 'UK' },
});
const reverse = await geocodeClient.reverseGeocode({
latlng: { lat: 51.5034, lng: -0.1276 },
resultType: ['street_address'],
});
Tip: Use the web service clients when you need typed access to Google Maps REST endpoints (for example SSR, background jobs, or prefetching data). For interactive map experiences, continue to use the on-map utilities that operate directly on the JavaScript SDK.
// Get directions
const directions = await getDirectionsAsync({
origin: string | LatLngLiteral;
destination: string | LatLngLiteral;
travelMode?: TravelMode;
waypoints?: DirectionsWaypoint[];
optimizeWaypoints?: boolean;
avoidHighways?: boolean;
avoidTolls?: boolean;
});
// Render directions
const renderer = renderDirections(map, directions);
clearDirections(renderer);
npm test
# Install dependencies
npm install
# Build packages
npm run build
# Run tests
npm run test
# Lint code
npm run lint
# Format code
npm run format
MIT License - see LICENSE file for details.
Contributions are welcome! Please read our contributing guidelines and submit pull requests to our repository.
For questions and support, please open an issue on our GitHub repository.
The React package provides 20 specialized hooks and components for Google Maps integration:
npm install @gmaps-kit/react @gmaps-kit/core
import { useGoogleMaps, useMap, Map } from '@gmaps-kit/react';
function App() {
const { isLoaded } = useGoogleMaps({
apiKey: 'YOUR_API_KEY',
libraries: ['places'],
});
const { map } = useMap({
center: { lat: 40.7128, lng: -74.006 },
zoom: 12,
});
if (!isLoaded) return <div>Loading...</div>;
return <Map mapInstance={map} />;
}
Core Hooks:
useGoogleMaps
- Load Google Maps SDKuseMap
- Map managementuseMarkers
- Marker managementuseMapEvents
- Map event handling
Geocoding Hooks:
useGeocoding
- Client-side geocodinguseGeocodingService
- Server-side geocoding
Places Hooks:
usePlaces
- Legacy Places APIusePlacesNew
- New Places API (New) π
Directions & Routing:
useDirections
- Route calculationsuseBicycling
- Bicycling layeruseTraffic
- Traffic layeruseTransit
- Transit layer
Advanced Features:
useClustering
- Marker clusteringuseDistanceMatrix
- Distance calculationsuseElevation
- Elevation datauseGeometry
- Geometric calculationsuseHeatmap
- Heatmap visualizationuseInfoWindows
- InfoWindow managementuseMaxZoom
- Zoom managementuseStreetView
- Street View functionality
Map
- Google Maps componentMarker
- Marker componentInfoWindow
- InfoWindow component
Note: Vue and Angular wrappers will be added in future phases.