mapcn-react-native
Core

Markers

MapMarker, MarkerContent, and MarkerLabel -- native-anchored markers with custom content and text labels.

Renderer support: MapLibre ✓ (⚠ allowOverlap is a documented no-op)  ·  Mapbox ✓

npx mapcn-rn add marker
import { MapMarker, MarkerContent, MarkerLabel } from "@/components/ui/mapcn";

Overview

MapMarker is one of the four renderer-specific files (along with map.tsx, map-renderer.tsx, and map-location-puck.tsx) -- MapLibre's Marker takes a string anchor ("top-left", "center", ...) while Mapbox's MarkerView takes an {x, y} anchor and understands allowOverlap natively. mapcn's MapMarker normalizes both to the same {x, y} prop.

MapMarker uses native marker views, which is the right tool up to roughly a hundred markers. Past that, switch to GeoJSON or Clustering -- both render through native map layers instead of one React Native view per point, and stay correct at 10k+ points.

Props

PropTypeDefaultDescription
coordinate[number, number][longitude, latitude]. Mutually exclusive with longitude/latitude.
longitude / latitudenumberAlternative to coordinate.
childrenReactNodea default dotCustom marker content.
labelstringText label rendered via MarkerLabel.
anchor{ x: number; y: number }{ x: 0.5, y: 0.5 }Anchor point, 0.01.0 on each axis.
allowOverlapbooleanfalseHonored on Mapbox. No MapLibre equivalent -- accepted but a documented no-op there, not a silent drop.
onPress() => voidFires on marker press.

MarkerContent ({ children?, className? }) wraps custom marker content; without children it renders the same default dot as a bare MapMarker.

MarkerLabel ({ children, className?, classNameText?, position?: "top" | "bottom" }, default position: "top") renders a small text label anchored above or below the marker, positioned with a measured layout + transform rather than the web-style left-1/2/translate-x-[-50%] hack v1 used (which doesn't work correctly in React Native).

Example

import { Map } from "@/components/ui/mapcn";
import { MapMarker, MarkerContent, MarkerLabel } from "@/components/ui/mapcn";

const places = [
  { id: "sf", coordinate: [-122.4194, 37.7749] as const, label: "San Francisco" },
  { id: "oak", coordinate: [-122.2712, 37.8044] as const, label: "Oakland" },
];

export function MarkersExample() {
  return (
    <Map defaultViewport={{ center: [-122.35, 37.79], zoom: 10 }} className="flex-1">
      {places.map((place) => (
        <MapMarker key={place.id} coordinate={place.coordinate} onPress={() => console.log(place.id)}>
          <MarkerContent />
          <MarkerLabel>{place.label}</MarkerLabel>
        </MapMarker>
      ))}
    </Map>
  );
}

Live example

markers example screenshot

Renderer support

allowOverlap has no MapLibre equivalent and is accepted-but-ignored there, rather than pretending both renderers behave identically. MAP_LOCATION_PUCK_CAPABILITIES-style capability constants aren't needed for markers specifically since the gap is a single documented prop, not a whole feature area.

Popups · GeoJSON · Clustering

On this page