Skip to main content

Map

GmvMap renders a Google Maps map and exposes a mapPromise that resolves to the underlying google.maps.Map instance.

The component is exported as MapLayer from @gmap-vue/v3/components and registered by the plugin as GmvMap.

Basic usage​

Give the map an explicit width and height. Without height, the map can load but appear blank.

<script setup lang="ts">
import { ref } from "vue";

const center = ref({ lat: -34.6037, lng: -58.3816 });
</script>

<template>
<GmvMap :center="center" :zoom="12" style="width: 100%; height: 500px" />
</template>

Use reactive props first​

For data-driven UI changes, update Vue state and let GmvMap sync the Google Maps instance.

<script setup lang="ts">
import { ref } from "vue";

const center = ref({ lat: -34.6037, lng: -58.3816 });
const zoom = ref(12);

function moveToRecoleta() {
center.value = { lat: -34.5875, lng: -58.3974 };
zoom.value = 14;
}
</script>

<template>
<GmvMap :center="center" :zoom="zoom" style="width: 100%; height: 500px" />
<button @click="moveToRecoleta">Move to Recoleta</button>
</template>

Use the imperative map instance only when you need methods that are not represented by Vue props yet.

Access the map instance​

Use a template ref or the useMapPromise composable when you need the Google Maps object.

<script setup lang="ts">
import { useMapPromise } from "@gmap-vue/v3/composables";
import { ref } from "vue";

const center = ref({ lat: -34.6037, lng: -58.3816 });
const mapKey = "main-map";
const mapPromise = useMapPromise(mapKey);

async function handleTilesLoaded(): Promise<void> {
const map = await mapPromise;
if (!map) return;

console.log("center", map.getCenter());
console.log("zoom", map.getZoom());
console.log("bounds", map.getBounds());
}
</script>

<template>
<GmvMap
:map-key="mapKey"
:center="center"
:zoom="12"
style="width: 100%; height: 500px"
@tilesloaded="handleTilesLoaded"
/>
</template>

The string passed to useMapPromise(mapKey) must match the map's map-key prop. getBounds() can return undefined before the map is initialized or visible, so map events such as tilesloaded are safer places to read bounds, center, and zoom.

Use PlacesService​

Enable the places library in the plugin options before using google.maps.places.PlacesService. places is the plugin default, but explicit configuration makes the dependency clear.

main.ts excerpt
createGmapVuePlugin({
load: {
key: import.meta.env.VITE_GOOGLE_MAPS_API_KEY,
libraries: "places",
},
});

Then use the map promise before interacting with the map. Trigger Places requests from explicit user actions or controlled state, not high-frequency map render events.

<script setup lang="ts">
import {
useGoogleMapsApiPromiseLazy,
useMapPromise,
} from "@gmap-vue/v3/composables";
import { ref } from "vue";

const center = ref({ lat: -34.6037, lng: -58.3816 });
const mapKey = "places-map";
const mapPromise = useMapPromise(mapKey);

async function findPlace(): Promise<void> {
const google = await useGoogleMapsApiPromiseLazy();
const map = await mapPromise;
if (!google || !map) return;

const service = new google.maps.places.PlacesService(
document.createElement("div"),
);

service.findPlaceFromQuery(
{
query: "Teatro Colón Buenos Aires",
fields: ["name", "geometry"],
},
(results, status) => {
const location = results?.[0]?.geometry?.location;

if (status === google.maps.places.PlacesServiceStatus.OK && location) {
map.setCenter(location);
}
},
);
}
</script>

<template>
<GmvMap
:map-key="mapKey"
:center="center"
:zoom="12"
style="width: 100%; height: 500px"
/>
<button @click="findPlace">Find Teatro Colón</button>
</template>