Change cluster icon in Mapbox compose for Android
04:44 19 Sep 2025

I would like to set a specific icon for my clusters in mapbox but I can't find how to do this in compose. I found some tutorials to do this in classic Java but can't find how to adapt it to the compose sdk.

Here is my current implementation

@Composable
private fun Map() {
    val context = LocalContext.current
    val places = getGeoJsonFeatures(context)
    val mapViewportState = rememberMapViewportState {
        setCameraOptions {
            zoom(8.0)
            center(Point.fromLngLat(5.3673291, 43.2935499))
            pitch(0.0)
            bearing(0.0)
        }
    }
    var placeClicked: JsonElement? by remember { mutableStateOf(null) }
    
    MapboxMap(
        modifier = Modifier.fillMaxSize(),
        mapViewportState = mapViewportState,
    ) {
        val selectedPoiMarker =
            rememberIconImage(key = "selectedPoiMarker", painter = painterResource(R.drawable.selected_poi))
        val poiMarker =
            rememberIconImage(key = "poiMarker", painter = painterResource(R.drawable.ic_location))
        PointAnnotation(point = Point.fromLngLat(5.4345368, 43.3424593)) {
            iconImage = poiMarker
        }

        PointAnnotationGroup(
            annotations = places.map { place ->
                PointAnnotationOptions()
                    .withPoint(
                        Point.fromLngLat(
                            place.geometry.coordinates[0],
                            place.geometry.coordinates[1]
                        )
                    ).withData(Gson().toJsonTree(place.properties))
                    .withIconImage(getBitmap(context, R.drawable.poi))
            },
            annotationConfig = AnnotationConfig(
                annotationSourceOptions = AnnotationSourceOptions(
                    clusterOptions = ClusterOptions(
                        textColor = Color.BLACK,
                        textSize = 20.0,
                        circleRadiusExpression = literal(25.0),
                        colorLevels = listOf(
                            Pair(100, Color.RED),
                            Pair(50, Color.BLUE),
                            Pair(0, Color.GREEN)
                        )
                    )
                )
            ),
        ) {

            interactionsState
                .onClicked { point ->
                    placeClicked = point.getData()?.asJsonObject
                    true
                }
                .onClusterClicked { cluster ->
                    mapViewportState.easeTo(
                        cameraOptions {
                            center(cluster.originalFeature.geometry() as Point)
                            zoom((mapViewportState.cameraState?.zoom ?: 8.0) + 2.0)
                        }
                    )

                    true
                }
        }

        placeClicked?.let {
            PointAnnotation(point = Point.fromLngLat((it.asJsonObject.get("geometry") as GeoJsonGeometry).coordinates[0], (it.asJsonObject.get("geometry") as GeoJsonGeometry).coordinates[1])) {
                iconImage = selectedPoiMarker
            }
        }
    }
}

The places list is loaded from assets as GeoJson object list and added to the map as PointAnnotationGroup with CusterOptions to ensure that the list is displayed as clusters.

Moreover I would like to change the icon of a place clicked. I tried to add a PointAnnotation to draw above the existing icon but the app crashed. I guess the map has to rerender everything and cannot handle it.

Does anyone has some clues on how to change the cluster icon or the point clicked icon ? Maybe I'm not doing things right but this is the most logical way to implement it according to Mapbox's tutorials and samples.

kotlin android-jetpack-compose mapbox mapbox-android