---
title: "MaplibrePopup"
description: "A popup that renders content through its default slot, anchored at a reactive lnglat position."
canonical_url: "https://maplibre.mhaibaraai.cn/en/docs/core/popup"
---
# MaplibrePopup

> A popup that renders content through its default slot, anchored at a reactive lnglat position.

## Introduction

`MaplibrePopup` anchors a popup at the specified `lnglat`, rendering arbitrary content via the default slot. The position updates reactively when `lnglat` changes, and a `close` event is emitted when the popup is dismissed.

## Usage

The default slot renders the popup content, and maplibre options such as `options.closeOnClick` are forwarded directly:

```vue [PopupBasicExample.vue]
<script setup lang="ts">
import type { LngLatLike } from 'maplibre-gl'

const lnglat = ref<LngLatLike>([116.397, 39.908])
</script>

<template>
  <div class="h-115 w-full overflow-hidden rounded-(--ui-radius) border border-default">
    <MaplibreMap :options="{ style: 'https://tiles.openfreemap.org/styles/liberty', center: [116.397, 39.908], zoom: 13 }">
      <!-- 默认插槽渲染弹窗内容 -->
      <MaplibrePopup :lnglat="lnglat" :options="{ closeOnClick: false, offset: 12 }">
        <div class="px-1 py-0.5">
          <p class="font-semibold">
            天安门
          </p>
          <p class="text-sm text-muted">
            北京市东城区
          </p>
        </div>
      </MaplibrePopup>
    </MaplibreMap>
  </div>
</template>
```

## Examples

### Click to Set Position

Click the map to get coordinates, assign them to `lnglat`, and the popup repositions automatically:

```vue [PopupClickExample.vue]
<script setup lang="ts">
import type { LngLatLike, MapMouseEvent } from 'maplibre-gl'

const lnglat = ref<LngLatLike | null>(null)
const label = ref('')

// 点击地图取坐标，弹窗随之定位（同一 Popup 经 watch 增量更新位置）
function onClick(event: MapMouseEvent) {
  const { lng, lat } = event.lngLat
  lnglat.value = [lng, lat]
  label.value = `${lng.toFixed(4)}, ${lat.toFixed(4)}`
}
</script>

<template>
  <div class="h-115 w-full overflow-hidden rounded-(--ui-radius) border border-default">
    <MaplibreMap
      :options="{ style: 'https://tiles.openfreemap.org/styles/liberty', center: [116.397, 39.908], zoom: 12 }"
      @click="onClick"
    >
      <MaplibrePopup v-if="lnglat" :lnglat="lnglat" :options="{ offset: 8 }">
        <div class="px-1 py-0.5 text-sm">
          {{ label }}
        </div>
      </MaplibrePopup>
      <div v-if="!lnglat" class="absolute left-3 top-3 z-10 rounded-(--ui-radius) border border-default bg-default/80 px-3 py-1.5 text-sm backdrop-blur">
        点击地图任意位置
      </div>
    </MaplibreMap>
  </div>
</template>
```

### Multiple Popups

Render several `MaplibrePopup` components with `v-for` to keep a group of popups open at once. `closeOnClick` must be disabled, otherwise a single map click dismisses the whole group:

```vue [PopupGroupExample.vue]
<script setup lang="ts">
interface Poi {
  id: string
  lnglat: [number, number]
  name: string
}

const points: Poi[] = [
  { id: 'tam', lnglat: [116.397, 39.908], name: '天安门' },
  { id: 'gm', lnglat: [116.461, 39.909], name: '国贸' },
  { id: 'zgc', lnglat: [116.316, 39.983], name: '中关村' }
]
</script>

<template>
  <div class="h-115 w-full overflow-hidden rounded-(--ui-radius) border border-default">
    <MaplibreMap :options="{ style: 'https://tiles.openfreemap.org/styles/positron', center: [116.39, 39.94], zoom: 10.6 }">
      <MaplibrePopup
        v-for="point in points"
        :key="point.id"
        :lnglat="point.lnglat"
        :options="{ closeButton: false, closeOnClick: false, offset: 12 }"
      >
        <div class="px-1 text-sm font-semibold">
          {{ point.name }}
        </div>
      </MaplibrePopup>
    </MaplibreMap>
  </div>
</template>
```

> [!NOTE]
> 
> MaplibreTooltip
> 
>  holds a single Popup instance and cannot show several feature popups at once — its 
> 
> feature
> 
>  comes from mouse events, and the component does not hold the feature list. To keep layer-feature popups open simultaneously, iterate the source array that builds your GeoJSON and render one 
> 
> MaplibrePopup
> 
>  per point. If your points are DOM markers, 
> 
> MaplibreMarker
> 
>  with 
> 
> :open="true"
> 
>  is more direct.

## API

### Props

```ts
/**
 * Props for the MaplibrePopup component
 */
interface MaplibrePopupProps {
  /**
   * 弹窗锚定的经纬度
   */
  lnglat: LngLatLike;
  /**
   * Popup 选项；值变化时重建弹窗
   */
  options?: PopupOptions | undefined;
}
```

### Emits

```ts
/**
 * Emitted events for the MaplibrePopup component
 */
interface MaplibrePopupEmits {
  close: (payload: []) => void;
}
```

### Slots

```ts
/**
 * Slots for the MaplibrePopup component
 */
interface MaplibrePopupSlots {
  default(): any;
}
```

### Expose

Access the component instance via [`useTemplateRef`](https://vuejs.org/api/composition-api-helpers.html#usetemplateref).

| Name | Type |
| --- | --- |
| `popup` | `() => Popup \| undefined` <br> Returns the underlying maplibre-gl Popup instance |

## Changelog

See commit history for [src/runtime/components/MaplibrePopup.vue](https://github.com/mhaibaraai/movk-maplibre/commits/main/src/runtime/components/MaplibrePopup.vue).


## Sitemap

See the full [sitemap](https://maplibre.mhaibaraai.cn/sitemap.md) for all pages.
