Advanced
Access the underlying MapLibre GL instance for advanced customization.
Access the underlying MapLibre GL map instance to use any feature from the MapLibre GL JS API. You can use either a template ref or the useMap composable.
Using a Ref
The simplest way to access the map instance from a parent component. The Map component exposes its MapLibre instance via defineExpose.
<script setup lang="ts">
import { ref } from "vue";
import { Map, type MapRef } from "@/components/ui/map";
const mapRef = ref<{ map: { value: MapRef | null } } | null>(null);
const handleFlyTo = () => {
// Access the underlying MapLibre instance via the exposed `map` ref.
mapRef.value?.map?.value?.flyTo({ center: [-74, 40.7], zoom: 12 });
};
</script>
<template>
<button @click="handleFlyTo">Fly to NYC</button>
<Map ref="mapRef" :center="[-74, 40.7]" :zoom="10" />
</template>Using the Composable
For child components rendered inside Map, use the useMap composable to access the map instance and listen to events.
<script setup lang="ts">
import { Map, useMap } from "@/components/ui/map";
import { onBeforeUnmount, watch } from "vue";
// For child components inside <Map>, use the useMap composable.
function MapEventListener() {
const { map, isLoaded } = useMap();
let cleanup: (() => void) | null = null;
watch([map, isLoaded], ([m, loaded]) => {
cleanup?.();
cleanup = null;
if (!m || !loaded) return;
const handleClick = (e: maplibregl.MapMouseEvent) => {
console.log("Clicked at:", e.lngLat);
};
m.on("click", handleClick);
cleanup = () => m.off("click", handleClick);
});
onBeforeUnmount(() => cleanup?.());
}
</script>
<template>
<Map :center="[-74, 40.7]" :zoom="10">
<MapEventListener />
</Map>
</template>Example: Custom Controls
This example shows how to create custom controls that manipulate the map's pitch and bearing, and listen to map events to display real-time values.
<script setup lang="ts">
import { Mountain, RotateCcw } from "lucide-vue-next";
import MapControllerOverlay from "./advanced/MapControllerOverlay.vue";
</script>
<template>
<div class="h-[420px] w-full">
<ClientOnly>
<Map :center="[-73.9857, 40.7484]" :zoom="15">
<MapControllerOverlay />
</Map>
</ClientOnly>
</div>
</template>
Example: Custom GeoJSON Layer
Add custom GeoJSON data as layers with fill and outline styles. This example shows NYC parks with hover interactions.
<script setup lang="ts">
import CustomLayerOverlay from "./advanced/CustomLayerOverlay.vue";
</script>
<template>
<div class="h-[420px] w-full">
<ClientOnly>
<Map :center="[-73.97, 40.78]" :zoom="11.8">
<MapControls />
<CustomLayerOverlay />
</Map>
</ClientOnly>
</div>
</template>
Example: Markers via Layers
When displaying hundreds or thousands of markers, use GeoJSON layers instead of DOM-based MapMarker components. This approach renders markers on the WebGL canvas, providing significantly better performance.
<script setup lang="ts">
import LayerMarkersOverlay from "./advanced/LayerMarkersOverlay.vue";
</script>
<template>
<div class="h-[420px] w-full">
<ClientOnly>
<Map :center="[-73.98, 40.75]" :zoom="11">
<LayerMarkersOverlay />
</Map>
</ClientOnly>
</div>
</template>
Extend to Build
You can extend this to build custom features like:
- Real-time tracking — Live location updates for delivery, rides, or fleet management
- Geofencing — Trigger actions when users enter or leave specific areas
- Heatmaps — Visualize density data like population, crime, or activity hotspots
- Drawing tools — Let users draw polygons, lines, or place markers for custom areas
- 3D buildings — Extrude building footprints for urban visualization
- Animations — Animate markers along routes or create fly-through experiences
- Custom data layers — Overlay weather, traffic, or satellite imagery