Markers

Add markers with custom content, labels, tooltips, and popups.

Basic Example

#

Place markers with ng-map-marker. Project any HTML into ng-marker-content — leave it empty for the default dot. Add ng-marker-tooltip for hover and focus tooltips and ng-marker-label for always-visible labels.

import { Component } from '@angular/core';
import {
  MapComponent,
  MapMarkerComponent,
  MarkerContentComponent,
  MarkerLabelComponent,
  MarkerTooltipComponent,
} from 'ng-mapcn';

@Component({
  selector: 'app-markers-map',
  standalone: true,
  imports: [
    MapComponent,
    MapMarkerComponent,
    MarkerContentComponent,
    MarkerLabelComponent,
    MarkerTooltipComponent,
  ],
  template: `
    <div class="h-[420px]">
      <ng-map [center]="[139.6917, 35.6895]" [zoom]="10">
        @for (place of places; track place.name) {
          <ng-map-marker [longitude]="place.lng" [latitude]="place.lat">
            <ng-marker-content>
              <!-- empty = default blue dot; or project your own element -->
            </ng-marker-content>
            <ng-marker-tooltip>{{ place.name }}</ng-marker-tooltip>
          </ng-map-marker>
        }
      </ng-map>
    </div>
  `,
})
export class MarkersMapComponent {
  readonly places = [
    { name: 'Shibuya', lng: 139.7016, lat: 35.658 },
    { name: 'Shinjuku', lng: 139.7036, lat: 35.6938 },
    { name: 'Asakusa', lng: 139.7967, lat: 35.7118 },
  ];
}

Rich Popups

#

Attach a popup with ng-marker-popup. It opens when the marker is clicked and can contain any projected HTML — here with images, ratings, and action buttons. Only one is open at a time; clicking the map closes it. ng-marker-popup also takes [closeButton], offset, anchor, maxWidth and closeOnClick.

// A single ng-map-popup driven by a signal → only one open at a time.
// mapClick clears it (clicking a marker doesn't fire the map click).
selected = signal<RichPlace | null>(null);

selectPlace(place: RichPlace, event: MouseEvent) {
  event.stopPropagation(); // don't let it bubble to mapClick
  this.selected.set(this.selected()?.name === place.name ? null : place);
}

// template
<ng-map [center]="[-73.98, 40.74]" [zoom]="11" (mapClick)="selected.set(null)">
  @for (place of places; track place.name) {
    <ng-map-marker
      [longitude]="place.lng"
      [latitude]="place.lat"
      (markerClick)="selectPlace(place, $event)"
    >
      <ng-marker-content>
        <!-- a real <button>: focusable, and Enter/Space fire the same click as the mouse -->
        <button type="button" [attr.aria-label]="place.name" class="size-5 cursor-pointer rounded-full border-2 border-white bg-rose-500 shadow-lg transition-transform hover:scale-110"></button>
        <ng-marker-label position="bottom">{{ place.label }}</ng-marker-label>
      </ng-marker-content>
    </ng-map-marker>
  }

  @if (selected(); as place) {
    <ng-map-popup
      [longitude]="place.lng"
      [latitude]="place.lat"
      (popupClose)="selected.set(null)"
    >
      <!-- .demo-rich-popup lets the popup card go edge-to-edge (padding: 0) -->
      <div class="demo-rich-popup w-[15.5rem]">
        <img [src]="place.image" [alt]="place.name" class="h-32 w-full object-cover" />
        <div class="space-y-2 p-3">
          <p class="text-muted-foreground text-[11px] uppercase tracking-wide">{{ place.category }}</p>
          <h3 class="font-semibold leading-tight">{{ place.name }}</h3>
          <!-- rating · hours · Directions / link buttons -->
        </div>
      </div>
    </ng-map-popup>
  }
</ng-map>

Draggable Marker

#

Set draggable and listen to dragEnd to track the marker position. The marker also moves from the keyboard: focus it with Tab and use the arrow keys (Shift for a larger step); each key press emits dragEnd. Enter or Space trigger markerClick.

lng: -3.7038 lat: 40.4168 clicks: 0
import { Component, signal } from '@angular/core';
import {
  MapComponent,
  MapMarkerComponent,
  MarkerContentComponent,
} from 'ng-mapcn';

@Component({
  selector: 'app-draggable-marker',
  standalone: true,
  imports: [MapComponent, MapMarkerComponent, MarkerContentComponent],
  template: `
    <div class="h-[420px]">
      <ng-map [center]="[-3.7038, 40.4168]" [zoom]="12">
        <ng-map-marker
          [longitude]="-3.7038"
          [latitude]="40.4168"
          [draggable]="true"
          ariaLabel="Draggable marker"
          (dragEnd)="position.set($event)"
          (markerClick)="clicks.update((n) => n + 1)"
        >
          <ng-marker-content>
            <div class="size-4 cursor-grab rounded-full border-2 border-white bg-blue-500 shadow-lg"></div>
          </ng-marker-content>
        </ng-map-marker>
      </ng-map>
    </div>
  `,
})
export class DraggableMarkerComponent {
  readonly position = signal({ lng: -3.7038, lat: 40.4168 });
  readonly clicks = signal(0);
}