<ScriptGoogleMapsOverlayView>
Renders Vue slot content at a map latitude and longitude using Google's OverlayView. Unlike InfoWindow, it leaves the HTML structure and styling to you.
v-model:openbooleanMarker Anchoring
When nested inside a ScriptGoogleMapsMarker, the overlay inherits the marker's position and follows it while it is dragged.
<template>
<ScriptGoogleMaps api-key="your-api-key">
<ScriptGoogleMapsMarker
:position="{ lat: -34.397, lng: 150.644 }"
:options="{ gmpDraggable: true }"
>
<ScriptGoogleMapsOverlayView
anchor="bottom-center"
:offset="{ x: 0, y: -50 }"
>
<div class="custom-tooltip">
Custom Vue content
</div>
</ScriptGoogleMapsOverlayView>
</ScriptGoogleMapsMarker>
</ScriptGoogleMaps>
</template>
Controlled vs Uncontrolled Open State
The overlay supports two open-state patterns: uncontrolled (component-managed) and controlled (parent-managed via v-model:open).
Uncontrolled. The component owns its open state. The overlay opens by default; pass :default-open="false" to start closed. This is the simplest pattern when you don't need to react to state changes from the parent.
<template>
<!-- Opens immediately on mount (default) -->
<ScriptGoogleMapsOverlayView :position="{ lat: -34.397, lng: 150.644 }">
<div>Always-open label</div>
</ScriptGoogleMapsOverlayView>
<!-- Remains closed; use v-model:open when it needs to toggle -->
<ScriptGoogleMapsOverlayView
:position="{ lat: -34.397, lng: 150.644 }"
:default-open="false"
>
<div>Initially hidden</div>
</ScriptGoogleMapsOverlayView>
</template>
Controlled. Bind v-model:open to a parent ref. The parent owns the state and the overlay reflects it. The overlay updates the bound ref when something internal flips it (for example, the marker-cluster auto-hide behavior).
<script setup lang="ts">
const open = ref(true)
</script>
<template>
<ScriptGoogleMapsOverlayView v-model:open="open" :position="{ lat: -34.397, lng: 150.644 }">
<div>Controlled by parent</div>
</ScriptGoogleMapsOverlayView>
</template>
When v-model:open is bound, defaultOpen has no effect; pass an initial value to the bound ref instead.
An uncontrolled overlay that starts with defaultOpen: false has no public method for opening it later. Bind v-model:open for any overlay that needs to toggle.
Popup on Marker Click
Using v-model:open keeps the overlay mounted, toggling visibility via CSS. This avoids remount cost and preserves internal state.
<script setup lang="ts">
const open = ref(false)
</script>
<template>
<ScriptGoogleMaps api-key="your-api-key">
<ScriptGoogleMapsMarker
:position="{ lat: -34.397, lng: 150.644 }"
@click="open = !open"
>
<ScriptGoogleMapsOverlayView
v-model:open="open"
anchor="bottom-center"
:offset="{ x: 0, y: -50 }"
>
<div class="custom-popup">
<button @click.stop="open = false">
×
</button>
<p>Any Vue content here</p>
</div>
</ScriptGoogleMapsOverlayView>
</ScriptGoogleMapsMarker>
</ScriptGoogleMaps>
</template>
For simple cases where remounting is acceptable, v-if also works:
<ScriptGoogleMapsMarker
:position="{ lat: -34.397, lng: 150.644 }"
@click="open = true"
>
<ScriptGoogleMapsOverlayView v-if="open">
<MyPopup @close="open = false" />
</ScriptGoogleMapsOverlayView>
</ScriptGoogleMapsMarker>
Persistent Label
<template>
<ScriptGoogleMaps api-key="your-api-key">
<ScriptGoogleMapsOverlayView
:position="{ lat: -34.397, lng: 150.644 }"
anchor="center"
:block-map-interaction="false"
>
<span class="bg-white px-1.5 py-0.5 rounded">
Label text
</span>
</ScriptGoogleMapsOverlayView>
</ScriptGoogleMaps>
</template>
Position Format
The position prop accepts either a plain LatLngLiteral ({ lat, lng }) or a google.maps.LatLng instance, so you can pass values straight from the Maps API without converting them first.
<script setup lang="ts">
const mapRef = ref()
async function showSydney() {
// Resolve a query into a LatLng-shaped value via the Maps API
const sydney = await mapRef.value?.resolveQueryToLatLng('Sydney, Australia')
// Pass it through unchanged: works for both shapes
position.value = sydney
}
const position = ref()
</script>
<template>
<ScriptGoogleMaps ref="mapRef" api-key="your-api-key">
<ScriptGoogleMapsOverlayView v-if="position" :position="position">
<div>Resolved position</div>
</ScriptGoogleMapsOverlayView>
</ScriptGoogleMaps>
</template>
Map Panning
When an already-open overlay first attaches to the map, it pans into view with 40px of padding. Toggling a mounted overlay from closed to open does not currently run the pan step again.
To customize the padding or disable panning:
<!-- Custom padding -->
<ScriptGoogleMapsOverlayView :pan-on-open="60">
...
</ScriptGoogleMapsOverlayView>
<!-- Disable panning -->
<ScriptGoogleMapsOverlayView :pan-on-open="false">
...
</ScriptGoogleMapsOverlayView>
Cluster Awareness
When used inside a ScriptGoogleMapsMarkerClusterer, overlay views automatically hide when their parent marker joins a cluster on zoom out. This prevents orphaned overlays from floating over cluster icons.
When its marker is clustered, the overlay updates v-model:open to false. The user will need to reopen the overlay (e.g. click the marker again) after zooming back in.
To disable this behavior:
<ScriptGoogleMapsMarkerClusterer>
<ScriptGoogleMapsMarker :position="markerPosition">
<ScriptGoogleMapsOverlayView :hide-when-clustered="false">
...
</ScriptGoogleMapsOverlayView>
</ScriptGoogleMapsMarker>
</ScriptGoogleMapsMarkerClusterer>
Open-state animation
The overlay sets data-state="open" on its content wrapper while visible. Pass a class to the component to target that wrapper and animate its entrance:
<ScriptGoogleMapsOverlayView v-model:open="open" class="popup">
<div>
Animated popup
</div>
</ScriptGoogleMapsOverlayView>
<style>
.popup[data-state="open"] {
animation: fadeIn 200ms ease-out;
}
@keyframes fadeIn {
from { opacity: 0; transform: scale(0.95); }
to { opacity: 1; transform: scale(1); }
}
</style>
Closing sets the anchor to visibility: hidden immediately; the component does not wait for transitionend or animationend, so CSS exit animations are not visible. A template ref exposes dataState for code that needs the current state, but it is not a slot prop.
The blockMapInteraction prop (default true) calls google.maps.OverlayView.preventMapHitsAndGesturesFrom() to stop clicks, taps, and drags from propagating through the overlay to the map. Set it to false for non-interactive overlays like labels.