# rn-map URL: /docs/native/docyrus/map Compound map on react-native-maps with markers, callouts, circles, polylines, polygons, marker clustering, and map-type, zoom, locate and search controls. Falls back to a card when the module is missing. ## Installation ```bash pnpm dlx @docyrus/cli add @docyrus/rn-map ``` **Dependencies:** - [react-native-maps](https://www.npmjs.com/package/react-native-maps) - [@react-native-community/geolocation (optional)](https://www.npmjs.com/package/@react-native-community/geolocation) `react-native-maps` is an **optional peer**. It is loaded lazily. If it is not installed, ` ))} ); } ``` `` sorts its direct children. **Controls** (`MapZoomControl`, `MapLocateControl`, `MapTypeControl`, `MapSearchControl`, `MapSearchAreaControl`, `MapControlContainer`, and anything wrapped with `markMapControl()`) render in an overlay above the map. Everything else renders on the native map view. Fragments and arrays are flattened. ### Legacy convenience props The previous single-component API still works: ```tsx console.log(index, marker.title)} className="h-[240px]" /> ``` Changing `latitude`, `longitude` or `zoom` animates the camera. This applies only when neither `region` nor `initialRegion` is set. ### Driving it from a data hook The API is shaped so that a map-view hook (the web `useDocyrusMapView`) can drive it: | Hook concept | Map API | |--------------|---------| | `markers[]` with image / icon | `MapMarker` with a custom child view (`` / `DocyrusIcon`) and `tracksViewChanges={false}` once loaded | | basemap id (`street`, `satellite`, `hybrid`, `terrain`) | `mapType` (`standard`, `satellite`, `hybrid`, `terrain`) | | viewport bounds | `onRegionChangeComplete(region, { bounds, zoom })` | | "search this area" / `isViewportStale` | `MapSearchAreaControl visible onPress` | | `onMarkerMove` / `handleMarkerMove` | `MapMarker draggable onDragEnd(coordinate, id)` | | `onMapClick` | `onPress` / `onLongPress` | | `center` / `bounds` / fit | `fitToCoordinates` prop or `ref.fitToCoordinates()` | ## API Reference ### Map | Prop | Type | Default | Description | |------|------|---------|-------------| | `children` | `ReactNode` | — | Map layers and controls. | | `ref` | `Ref` | — | Imperative handle (React 19 ref-as-prop). See [MapHandle](#maphandle). | | `region` | `MapRegion` | — | Controlled region. Update it from `onRegionChangeComplete`. | | `initialRegion` | `MapRegion` | — | Uncontrolled initial region. | | `onRegionChange` | `(region: MapRegion) => void` | — | Fired continuously while the camera moves. | | `onRegionChangeComplete` | `(region: MapRegion, details: MapRegionChangeDetails) => void` | — | Fired when the camera settles. `details` carries `bounds`, `zoom` and `isGesture`. | | `fitToCoordinates` | `MapLatLng[]` | — | Fits the viewport to these coordinates whenever the list changes (after the map is ready). | | `fitPadding` | `number \| Partial` | `48` | Edge padding used by `fitToCoordinates` (the prop and the handle). | | `singlePointZoom` | `number` | `14` | Zoom used when fitting a single coordinate. | | `mapType` | `'standard' \| 'satellite' \| 'hybrid' \| 'terrain'` | — | Controlled map type. `terrain` needs the Google provider. | | `defaultMapType` | `MapType` | `'standard'` | Initial map type when uncontrolled. | | `onMapTypeChange` | `(mapType: MapType) => void` | — | Fired by `MapTypeControl` and by `useMap().setMapType`. | | `provider` | `'default' \| 'google'` | `'default'` | `'google'` forces Google Maps on iOS. | | `showsUserLocation` | `boolean` | `false` | Show the native user-location dot. | | `showsMyLocationButton` | `boolean` | `false` | Platform my-location button (Android Google Maps). | | `showsCompass` | `boolean` | `true` | Show the compass. | | `showsScale` | `boolean` | `false` | Show the scale bar. | | `showsBuildings` | `boolean` | `true` | Show 3D buildings. | | `showsTraffic` | `boolean` | `false` | Show traffic. | | `showsPointsOfInterest` | `boolean` | `true` | Show points of interest. | | `zoomEnabled` | `boolean` | `true` | Allow pinch zoom. | | `scrollEnabled` | `boolean` | `true` | Allow panning. | | `rotateEnabled` | `boolean` | `true` | Allow rotation. | | `pitchEnabled` | `boolean` | `true` | Allow pitch. | | `minZoomLevel` | `number` | — | Minimum zoom level. | | `maxZoomLevel` | `number` | — | Maximum zoom level. | | `onPress` | `(coordinate: MapLatLng) => void` | — | Tap on the map (marker taps are filtered out). | | `onLongPress` | `(coordinate: MapLatLng) => void` | — | Long-press on the map, for example to drop a pin. | | `onMapReady` | `() => void` | — | The native map finished loading. | | `fallback` | `ReactNode` | — | Rendered instead of the default card when `react-native-maps` is missing. | | `className` | `string` | — | Container classes. Give the map a height (`h-[320px]`, `flex-1`). | | `latitude` | `number` | `0` | Legacy. Center latitude. | | `longitude` | `number` | `0` | Legacy. Center longitude. | | `zoom` | `number` | `10` | Legacy. Zoom level. | | `markers` | `MapMarkerItem[]` | — | Legacy. Plain markers with a default callout. | | `onMarkerPress` | `(index: number, marker: MapMarkerItem) => void` | — | Legacy. Press on a `markers` entry. | ### MapHandle | Method | Signature | Description | |--------|-----------|-------------| | `animateToRegion` | `(region: MapRegion, duration?: number) => void` | Animates to a region (350 ms by default). | | `animateCamera` | `(camera: Partial, duration?: number) => void` | Animates heading, pitch, center or zoom. | | `fitToCoordinates` | `(coordinates: MapLatLng[], options?: MapFitOptions) => void` | Fits the viewport. A single coordinate centers on it at `singlePointZoom`. | | `zoomIn` / `zoomOut` | `() => void` | Zooms one level. Region-based, so it works on Apple and Google maps. | | `setZoom` | `(zoom: number) => void` | Absolute zoom that keeps the current center. | | `getRegion` | `() => MapRegion \| null` | Last settled region. | | `getBounds` | `() => MapBounds \| null` | Last settled bounds. | | `getCamera` | `() => Promise` | Native camera. | ### MapMarker | Prop | Type | Default | Description | |------|------|---------|-------------| | `coordinate` | `MapLatLng` | — | Marker position. Required. | | `id` | `string` | — | Stable id. Passed to the press and drag callbacks. | | `title` | `string` | — | Default-callout title. | | `description` | `string` | — | Default-callout description. | | `children` | `ReactNode` | — | Custom marker view and/or a `MapCallout`. | | `image` | `ImageSourcePropType` | — | Bitmap marker image (faster than a custom view). | | `pinColor` | `string` | — | Tint of the default pin. | | `anchor` | `{ x: number; y: number }` | — | Anchor point of the marker view, in `[0, 1]` space. | | `calloutAnchor` | `{ x: number; y: number }` | — | Anchor point of the callout. | | `tracksViewChanges` | `boolean` | platform default (`true`) | Re-render the custom view. Set `false` once it is static, for performance. | | `draggable` | `boolean` | — | Long-press to drag. | | `onDragStart` | `(coordinate: MapLatLng, id?: string) => void` | — | Drag started. | | `onDrag` | `(coordinate: MapLatLng, id?: string) => void` | — | While dragging. | | `onDragEnd` | `(coordinate: MapLatLng, id?: string) => void` | — | Drag ended with the new coordinate. | | `onPress` | `(coordinate: MapLatLng, id?: string) => void` | — | Marker press. | | `onCalloutPress` | `() => void` | — | Press on the callout. | | `opacity` | `number` | — | Marker opacity. | | `flat` | `boolean` | — | Flat against the map (rotates with it). | | `rotation` | `number` | — | Rotation in degrees. | | `zIndex` | `number` | — | Stacking order. | | `stopPropagation` | `boolean` | — | Keep the press from reaching the map's `onPress`. | ### MapCallout (alias `MapPopup`) | Prop | Type | Default | Description | |------|------|---------|-------------| | `children` | `ReactNode` | — | Callout content. | | `tooltip` | `boolean` | `true` | `true` renders a themed popover bubble. `false` uses the native callout bubble. | | `onPress` | `() => void` | — | Press on the callout. | | `className` | `string` | — | Classes for the content wrapper. | ### MapCircle | Prop | Type | Default | Description | |------|------|---------|-------------| | `center` | `MapLatLng` | — | Center. Required. | | `radius` | `number` | — | Radius in meters. Required. | | `strokeColor` | `string` | theme `primary` | Outline color. | | `fillColor` | `string` | `primary` at 15% | Fill color. | | `strokeWidth` | `number` | `2` | Outline width. | | `lineDashPattern` | `number[]` | — | Dash pattern. | | `zIndex` | `number` | — | Stacking order. | | `tappable` | `boolean` | `Boolean(onPress)` | Receive taps. | | `onPress` | `() => void` | — | Tap handler. | ### MapPolyline | Prop | Type | Default | Description | |------|------|---------|-------------| | `coordinates` | `MapLatLng[]` | — | Path. Required. | | `strokeColor` | `string` | theme `primary` | Line color. | | `strokeColors` | `string[]` | — | Per-vertex gradient (same length as `coordinates`). | | `strokeWidth` | `number` | `3` | Line width. | | `lineDashPattern` | `number[]` | — | Dash pattern. | | `lineCap` | `'butt' \| 'round' \| 'square'` | `'round'` | Line cap. | | `lineJoin` | `'miter' \| 'round' \| 'bevel'` | `'round'` | Line join. | | `geodesic` | `boolean` | — | Follow the earth's curvature. | | `zIndex` | `number` | — | Stacking order. | | `tappable` | `boolean` | `Boolean(onPress)` | Receive taps. | | `onPress` | `() => void` | — | Tap handler. | ### MapPolygon | Prop | Type | Default | Description | |------|------|---------|-------------| | `coordinates` | `MapLatLng[]` | — | Outer ring. Required. | | `holes` | `MapLatLng[][]` | — | Inner rings. | | `strokeColor` | `string` | theme `primary` | Outline color. | | `fillColor` | `string` | `primary` at 15% | Fill color. | | `strokeWidth` | `number` | `2` | Outline width. | | `lineDashPattern` | `number[]` | — | Dash pattern. | | `geodesic` | `boolean` | — | Geodesic edges. | | `zIndex` | `number` | — | Stacking order. | | `tappable` | `boolean` | `Boolean(onPress)` | Receive taps. | | `onPress` | `() => void` | — | Tap handler. | ### MapMarkerClusterGroup Clusters its `MapMarker` children with a zero-dependency screen-space grid. The grid is recomputed every time the map settles. | Prop | Type | Default | Description | |------|------|---------|-------------| | `children` | `ReactNode` | — | `MapMarker` elements. Children without a `coordinate` render untouched. | | `radius` | `number` | `60` | Grid cell size in screen px. Markers in one cell merge. | | `minPoints` | `number` | `2` | Minimum number of members that form a cluster. | | `maxZoom` | `number` | `18` | At or above this zoom level, clustering is disabled. | | `enabled` | `boolean` | `true` | Turn clustering off. | | `icon` | `(markerCount: number) => ReactNode` | primary count bubble | Custom cluster view. | | `onClusterPress` | `(cluster: MapCluster) => void` | zoom to fit members | Press on a cluster. | ### Controls All controls accept `position` (an absolute-position className string, as on web) and `className`. | Component | Props | Default `position` | Description | |-----------|-------|--------------------|-------------| | `MapControlContainer` | `children`, `position`, `className` | `'top-2 left-2'` | Generic overlay slot. | | `MapZoomControl` | `position`, `className` | `'top-2 left-2'` | + / − buttons. | | `MapLocateControl` | `position`, `className`, `watch?: boolean` (`false`), `zoom?: number` (`15`), `onLocationFound?(coordinate)`, `onLocationError?(error)` | `'bottom-2 right-2'` | Centers on the device and shows a pulse marker. Press again to stop tracking. | | `MapTypeControl` (alias `MapLayersControl`) | `position`, `className`, `mapTypes?: MapType[]` (all four), `labels?: Partial>` | `'top-2 right-2'` | Map-type action sheet. | | `MapSearchControl` | every `PlaceAutocomplete` prop, plus `position` and `zoom?: number` (`14`) | `'top-2 left-2 right-14'` | Place search that recenters the map. | | `MapSearchAreaControl` | `visible?: boolean` (`true`), `onPress` (required), `loading?: boolean` (`false`), `label?: string`, `position`, `className` | `'top-3 left-0 right-0 items-center'` | Floating "Search this area" pill. | ### Hooks and helpers | Export | Description | |--------|-------------| | `useMap()` | Context of the surrounding `` (`MapContextValue \| null`): `available`, `region`, `bounds`, `zoom`, `size`, `mapType`, `setMapType`, `locatedCoordinate`, `setLocatedCoordinate`, `userLocation`, `handle`. | | `markMapControl(Component)` | Flags a custom component as a control so `` renders it in the overlay. | | `regionFromCenter(center, zoom)` | Region around a point for a zoom level. | | `regionToBounds(region)` / `boundsToRegion(bounds)` | Region ⇄ `{ north, south, east, west }`. | | `coordinatesToRegion(coordinates, margin?)` | Region that contains every coordinate. | | `isInBounds(coordinate, bounds)` | Point-in-bounds test for viewport filtering. | | `zoomToDelta(zoom)` / `deltaToZoom(longitudeDelta)` | Web-mercator zoom ⇄ longitude delta (`360 / 2^zoom`). | ## Translations | Key | English fallback | |-----|------------------| | `ui.map.zoomControls` / `ui.map.zoomIn` / `ui.map.zoomOut` | Zoom controls / Zoom in / Zoom out | | `ui.map.selectLayers` | Select layers | | `ui.map.mapTypeStandard` / `…Satellite` / `…Hybrid` / `…Terrain` | Standard / Satellite / Hybrid / Terrain | | `ui.map.trackLocation` / `ui.map.stopTracking` / `ui.map.locating` | Track location / Stop tracking / Locating... | | `ui.mapView.searchThisArea` | Search this area | | `ui.map.notAvailable` / `ui.map.installHint` / `ui.map.markerCount` | Map not available / Install react-native-maps to display the map. / `{count}` markers | ## Components | Component | Description | |-----------|-------------| | `Map` | Root: native map, overlay controls, context. | | `MapMarker` | Marker with a custom view, drag support and a callout. | | `MapCallout` / `MapPopup` | Marker popup. | | `MapCircle` / `MapPolyline` / `MapPolygon` | Shapes. | | `MapMarkerClusterGroup` | Marker clustering. | | `MapControlContainer`, `MapZoomControl`, `MapLocateControl`, `MapTypeControl` / `MapLayersControl`, `MapSearchControl`, `MapSearchAreaControl` | Overlay controls. | Not ported from web: `MapTileLayer` / `MapLayers` / `MapLayerGroup` / `MapFeatureGroup` (the platform provider draws tiles, so use `mapType`), `MapFullscreenControl` (present a full-screen route instead), `MapCircleMarker` / `MapRectangle` (use `MapCircle` / `MapPolygon`), `MapTooltip` (use `MapCallout`), and the `MapDraw*` tools. ## Type Exports | Type | Description | |------|-------------| | `MapProps` | Props of `Map`. | | `MapHandle` | Imperative handle. | | `MapLatLng` | `{ latitude, longitude }`. | | `MapRegion` | `MapLatLng` plus `latitudeDelta` and `longitudeDelta`. | | `MapBounds` | `{ north, south, east, west }`. | | `MapCamera` | `{ center, heading, pitch, zoom?, altitude? }`. | | `MapEdgePadding` | `{ top, right, bottom, left }`. | | `MapFitOptions` | `{ padding?, animated? }`. | | `MapRegionChangeDetails` | `{ isGesture?, bounds, zoom }`. | | `MapType` | `'standard' \| 'satellite' \| 'hybrid' \| 'terrain'`. | | `MapProvider` | `'default' \| 'google'`. | | `MapMarkerItem` | Legacy `markers` item (was named `MapMarker`). | | `MapMarkerProps`, `MapCalloutProps`, `MapCircleProps`, `MapPolylineProps`, `MapPolygonProps` | Layer props. | | `MapMarkerClusterGroupProps`, `MapCluster` | Clustering props and a cluster record (`id`, `coordinate`, `count`, `coordinates`, `keys`). | | `MapControlContainerProps`, `MapZoomControlProps`, `MapLocateControlProps`, `MapTypeControlProps`, `MapSearchControlProps`, `MapSearchAreaControlProps` | Control props. | | `MapContextValue` | Value returned by `useMap()`. |