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:
| Prop | Default | Description |
|---|---|---|
radius | ~6% of screen width | Cluster radius in pixels |
minPoints | 2 | Minimum points to form a cluster |
minZoom | 1 | Minimum zoom level |
maxZoom | 20 | Maximum zoom level for clustering |
extent | 512 | Tile extent (supercluster) |
nodeSize | 64 | KD-tree leaf size |
clusteringEnabled | true | Toggle clustering |
spiralEnabled | true | Spider layout at max zoom |
spiderLineColor | #FF0000 | Color of spider connector lines |
clusterColor | #0F52FF | Default cluster bubble color (GMI brand blue) |
clusterTextColor | #FFFFFF | Default cluster label color |
clusterFontFamily | — | Font family for cluster count label |
animationEnabled | true | Animate cluster changes (iOS only) |
layoutAnimationConf | 200ms easeInEaseOut create/delete + scale update | LayoutAnimation config when animationEnabled (tuned for cluster bubble transitions; pass a custom config to override) |
clusterFadeInDuration | 250 | Cross-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 |
tracksViewChanges | false | Forwarded to default cluster markers |
edgePadding | 50px each side | Padding for fitToCoordinates on cluster press |
preserveClusterPressBehavior | false | Skip auto fitToCoordinates on cluster press |
selectedClusterId | — | Highlight a cluster by id |
selectedClusterColor | #FF5722 | Color when cluster is selected |
width / height | window size | Seed map dimensions before onLayout |
clusterUpdateIntervalMs | 100 | Minimum interval (ms) between cluster recomputations while the map is moving; 0 recomputes only on settle |
superClusterRef | — | Ref to access the underlying Supercluster engine |
mapRef | — | Callback ref to the inner react-native-maps instance |
Callbacks
| Prop | Signature | Description |
|---|---|---|
onClusterPress | (cluster, markers) => void | Fired when a cluster is tapped |
onMarkersChange | (markers) => void | Fired when visible markers/clusters change: once the first index has loaded, then only when the visible set changes. A re-render with the same marker coordinates does not fire it, so onMarkersChange={setState} is safe |
onRegionChangeComplete | (region, details, markers) => void | Extends the maps callback with current markers |
onError | (error) => void | Fired when the native cluster index fails to build, for example because the app was not rebuilt after installing the library. Markers from an earlier successful build keep showing. Without it, the error is thrown during render so an error boundary (and LogBox in development) shows it — see Troubleshooting |
Per-marker opt-out
Markers cluster by default (cluster omitted or cluster={true}). 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.