> ## Documentation Index
> Fetch the complete documentation index at: https://developers.zite.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Maps & address picker

> Render a Google Map, drop markers, and geocode addresses with the googlemaps integration — the API key is injected for you.

Connect the **googlemaps** [integration](/concepts/integrations-secrets) and the API key is injected as `import.meta.env.VITE_GOOGLEMAPS_API_KEY` — no workflow or fetch needed. `@googlemaps/js-api-loader` and `@types/google.maps` are pre-installed.

## The map component

```tsx theme={null}
// apps/<app>/src/components/MapComponent.tsx
import { useEffect, useRef, useState } from 'react';
import { Loader } from '@googlemaps/js-api-loader';

export default function MapComponent() {
  const mapRef = useRef<HTMLDivElement>(null);
  const mapInstanceRef = useRef<google.maps.Map | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState<string>();

  const apiKey = import.meta.env.VITE_GOOGLEMAPS_API_KEY;

  useEffect(() => {
    if (!apiKey) {
      setIsLoading(false);
      setError('Google Maps not connected. Connect it from the app\'s Integrations button.');
      return;
    }
    if (mapInstanceRef.current) { setIsLoading(false); return; }

    let mounted = true;
    const loader = new Loader({ apiKey, version: 'weekly' });
    loader.importLibrary('maps').then(({ Map }) => {
      if (!mounted || !mapRef.current || mapInstanceRef.current) return;
      mapInstanceRef.current = new Map(mapRef.current, {
        center: { lat: 37.7749, lng: -122.4194 },
        zoom: 12,
      });
      setIsLoading(false);
    }).catch((err) => {
      if (mounted) { setIsLoading(false); setError('Failed to load Google Maps'); console.error(err); }
    });
    return () => { mounted = false; };
  }, [apiKey]);

  // Always render the map container; overlay loading/error on top of it.
  return (
    <div className="relative w-full h-[400px]">
      <div ref={mapRef} className="w-full h-full" />
      {isLoading && (
        <div className="absolute inset-0 flex items-center justify-center bg-background/80 text-muted-foreground">
          Loading map…
        </div>
      )}
      {error && (
        <div className="absolute inset-0 flex items-center justify-center bg-background p-4 text-destructive">
          {error}
        </div>
      )}
    </div>
  );
}
```

Then drop it anywhere: `<MapComponent />`.

## Markers and geocoding

```ts theme={null}
const map = new google.maps.Map(mapRef.current, { center, zoom: 12 });

// Add a marker
new google.maps.Marker({ position: center, map });

// Geocode an address, then recenter — the basis of an address picker / store locator
const geocoder = new google.maps.Geocoder();
geocoder.geocode({ address: '1600 Amphitheatre Pkwy, Mountain View, CA' }, (results, status) => {
  if (status === google.maps.GeocoderStatus.OK && results) {
    map.setCenter(results[0].geometry.location);
  }
});
```

## Gotchas

* **Always render the map container** — never conditionally. If the `ref` div isn't in the DOM, `mapRef.current` is null and the map never initializes. Overlay loading/error states on top instead.
* **Give the container an explicit height** (e.g. `h-[400px]`), or the map renders at zero height.
