Skip to main content

MapView

The main export — a clustered MapView with the same API as react-native-map-clustering.

import MapView from 'react-native-better-clustering'
import { Marker } from 'react-native-maps'

react-native-better-clustering/compat is a backwards-compatible alias of the same component.

Basic usage

<MapView
style={{ flex: 1 }}
initialRegion={{
latitude: 52.23,
longitude: 21.01,
latitudeDelta: 0.35,
longitudeDelta: 0.35,
}}
radius={56}
minPoints={2}
clusterColor="#FFCC00"
clusterTextColor="#000000"
>
{points.map((point) => (
<Marker
key={point.id}
coordinate={{
latitude: point.latitude,
longitude: point.longitude,
}}
/>
))}
</MapView>

Clustering props

All standard react-native-maps MapView props are supported, plus:

PropDefaultDescription
radius~6% of screen widthCluster radius in pixels
minPoints2Minimum points to form a cluster
minZoom1Minimum zoom level
maxZoom20Maximum zoom level for clustering
extent512Tile extent (supercluster)
nodeSize64KD-tree leaf size
clusteringEnabledtrueToggle clustering
spiralEnabledtrueSpider layout at max zoom
spiderLineColor#FF0000Color of spider connector lines
clusterColor#0F52FFDefault cluster bubble color (GMI brand blue)
clusterTextColor#FFFFFFDefault cluster label color
clusterFontFamilyFont family for cluster count label
animationEnabledtrueAnimate cluster changes (iOS only)
layoutAnimationConf200ms easeInEaseOut create/delete + scale updateLayoutAnimation config when animationEnabled (tuned for cluster bubble transitions; pass a custom config to override)
clusterFadeInDuration250Cross-fade duration (ms) for default cluster bubbles on zoom: new bubbles fade in while removed ones linger and fade out, eliminating the blink from native annotations being added/removed (iOS + Android). Driven by Reanimated on the UI thread. The fade-out cross-fade is applied to the settled cluster set only — during an active pinch/pan, removed bubbles are dropped immediately so a continuous zoom does not stack multiple bubble generations and overload the JS thread. Gated by animationEnabled; ignored with a custom renderCluster. Set to 0 to disable
tracksViewChangesfalseForwarded to default cluster markers
edgePadding50px each sidePadding for fitToCoordinates on cluster press
preserveClusterPressBehaviorfalseSkip auto fitToCoordinates on cluster press
selectedClusterIdHighlight a cluster by id
selectedClusterColor#FF5722Color when cluster is selected
width / heightwindow sizeSeed map dimensions before onLayout
clusterUpdateIntervalMs100Minimum interval (ms) between cluster recomputations while the map is moving; 0 recomputes only on settle
superClusterRefRef to access the underlying Supercluster engine
mapRefCallback ref to the inner react-native-maps instance

Callbacks

PropSignatureDescription
onClusterPress(cluster, markers) => voidFired when a cluster is tapped
onMarkersChange(markers) => voidFired when visible markers/clusters change
onRegionChangeComplete(region, details, markers) => voidExtends the maps callback with current markers

Per-marker opt-out

Exclude individual markers from clustering:

<Marker
cluster={false}
coordinate={{ latitude: 52.23, longitude: 21.01 }}
/>

Custom cluster UI

Pass renderCluster for full control over the cluster bubble:

import MapView, {
type RenderClusterProps,
} from 'react-native-better-clustering'
import { Marker } from 'react-native-maps'

const renderCluster = (cluster: RenderClusterProps) => {
const [longitude, latitude] = cluster.geometry.coordinates

return (
<Marker
coordinate={{ latitude, longitude }}
onPress={cluster.onPress}
tracksViewChanges={cluster.tracksViewChanges}
>
{/* your cluster bubble */}
</Marker>
)
}

<MapView renderCluster={renderCluster} {...props}>
{/* markers */}
</MapView>

Cluster features include properties.point_count, properties.point_count_abbreviated, and properties.getExpansionRegion() for zoom-on-tap.

Types

import type {
ClusteredMapViewProps,
RenderClusterProps,
} from 'react-native-better-clustering'

ClusteredMapViewProps is the full props type for the clustered MapView.