<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.
positiongoogle.maps.LatLng | google.maps.LatLngLiteralGeographic position for the overlay. Falls back to parent marker position if omitted. Accepts either a plain `LatLngLiteral` (`{ lat, lng }`) or a `google.maps.LatLng` instance.
defaultOpenboolean = trueInitial open state for the uncontrolled mode (when `v-model:open` is not bound). When omitted, the overlay opens on mount, matching v0 behaviour. Has no effect when `v-model:open` is used; pass an initial value to the bound ref instead.
anchorScriptGoogleMapsOverlayAnchor = 'bottom-center'Anchor point of the overlay relative to its position.
offset{ x: number, y: number }Pixel offset from the anchor position.
paneScriptGoogleMapsOverlayPane = 'floatPane'The map pane on which to render the overlay.
zIndexnumberCSS z-index for the overlay element.
blockMapInteractionboolean = trueWhether to block map click and gesture events from passing through the overlay.
panOnOpenboolean | number = truePan the map so the overlay is fully visible when opened, similar to InfoWindow behavior. Set to `true` for default 40px padding, or a number for custom padding.
hideWhenClusteredboolean = trueAutomatically hide the overlay when its parent marker joins a cluster (on zoom out). Only applies when nested inside a ScriptGoogleMapsMarkerClusterer.
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.
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.