Location puck
The location puck shown on the map. Capability-gated props are documented, not faked.
Renderer support: MapLibre ✓ (⚠ pulsing/scale/images are Mapbox-only) · Mapbox ✓ (⚠ onPress/custom children are MapLibre-only)
npx mapcn-rn add location-puckimport { MapLocationPuck, MAP_LOCATION_PUCK_CAPABILITIES } from "@/components/ui/mapcn";Overview
MapLocationPuck is one of the four renderer-specific files. MapLibre renders its own JS <UserLocation> component (which can host custom children and an onPress handler); Mapbox renders its native <LocationPuck> (which supports pulsing, a custom scale, and custom top/bearing/shadow images). Neither renderer's feature set is faked on the other -- unsupported props are accepted (so the prop type stays uniform) but produce a __DEV__ console warning and have no effect, and MAP_LOCATION_PUCK_CAPABILITIES (a per-renderer RendererCapabilities object) lets you branch on what's actually supported at runtime.
follow is implemented as camera recentering on every location update (via useMap().flyTo) rather than wiring into Camera's native trackUserLocation/followUserLocation prop, which is declarative and owned by Map's own <Camera> element and not reachable from a sibling component. This is a documented simplification: visually equivalent to native follow for "keep the puck centered," at the cost of one extra location subscription while follow is active.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
visible | boolean | true | |
bearing | "none" | "heading" | "course" | "none" | Bearing source for the puck's directional indicator. |
accuracyRing | boolean | true | Shows an accuracy ring around the puck. |
minDisplacement | number | — | Meters between position updates. |
follow | false | "position" | "heading" | "course" | false | Recenters the camera on every location update while set. |
onFollowChange | (follow) => void | — | Fires whenever the camera is recentered due to follow. |
requestPermission | boolean | true | Requests foreground location permission on mount. |
onPermissionDenied | () => void | — | |
pulsing | boolean | { color?, radius?: number | "accuracy" } | — | Mapbox only. |
scale | number | — | Mapbox only. |
images | { top?, bearing?, shadow? } | — | Mapbox only. Custom puck images. |
onPress | () => void | — | MapLibre only. |
children | ReactNode | — | MapLibre only. Fully custom JS-rendered puck. |
className | string | — |
Example
import { Map } from "@/components/ui/mapcn";
import { MapLocationPuck } from "@/components/ui/mapcn";
export function LiveLocation() {
return (
<Map defaultViewport={{ center: [-122.4194, 37.7749], zoom: 14 }} className="flex-1">
<MapLocationPuck bearing="heading" follow="position" pulsing={{ color: "#4285F4" }} />
</Map>
);
}Renderer support
interface RendererCapabilities {
clusterMinPoints: boolean;
locationPuckPulsing: boolean; // Mapbox: true, MapLibre: false
locationPuckScale: boolean; // Mapbox: true, MapLibre: false
locationPuckImages: boolean; // Mapbox: true, MapLibre: false
locationPuckPress: boolean; // Mapbox: false, MapLibre: true
locationPuckCustomChildren: boolean; // Mapbox: false, MapLibre: true
}