The <x-map-cluster-layer> component efficiently handles large numbers of markers by grouping them into clusters. As you zoom in, clusters break apart into individual points. This is the recommended approach for datasets with hundreds or thousands of points.
Pass an array of GeoJSON Features to the :data prop. Click on clusters to zoom in:
Instead of passing an array, you can point to a remote GeoJSON file. MapLibre will fetch and cluster the data client-side:
Change the cluster circle color to match your brand:
The :data prop accepts an array of GeoJSON Feature objects. Each feature must have:
[
'type' => 'Feature',
'properties' => [
'name' => 'Location Name', // Any properties you want
],
'geometry' => [
'type' => 'Point',
'coordinates' => [$lng, $lat], // [longitude, latitude]
],
]
| Prop | Type | Default | Description |
|---|---|---|---|
| :data | array | [] | GeoJSON Features or raw items |
| url | ?string | null | URL to GeoJSON file (client-side fetch) |
| id | ?string | null | Unique ID for events/updates |
| :cluster-max-zoom | int | 14 | Max zoom level to cluster at |
| :cluster-radius | int | 50 | Pixel radius to group points |
| :cluster-min-points | int | 2 | Min points to form a cluster |
| cluster-color | string | '#1A56DB' | Color of the cluster circle |
| cluster-text-color | string | '#FFFFFF' | Color of the count text |
| :cluster-size-stops | array | [[0, 30], [100, 40], [1000, 50]] | Circle radius based on point count |
| point-color | string | '#1A56DB' | Color of unclustered point |
| :point-radius | int | 6 | Radius of unclustered point |
| :show-count | bool | true | Show point count in clusters |
| popup-property | ?string | null | Property to show in popup |
| popup-template | ?string | null | Inline HTML popup template |
| :click-zoom | bool | true | Zoom in on cluster click |
| :buffer | int | 256 | Tile buffer |
| :tolerance | float | 0.5 | Simplification tolerance |
| :max-features-to-inline | int | 2000 | Max features to pass via props |
| class | string | '' | Additional CSS classes |
Customize the popup shown when clicking unclustered points.
The recommended approach is using the popup slot. Use {property} placeholders for dynamic data:
<x-map-cluster-layer :data="$locations"> <x-slot:popup> <div class="p-3"> <h3 class="font-bold">{name}</h3> <p class="text-xs">{address}</p> <p class="text-[10px] text-gray-400 mt-2">{lat}, {lng}</p> </div> </x-slot:popup> </x-map-cluster-layer>
Update cluster data without a full Livewire re-render by dispatching a map event from your PHP component. Each cluster layer listens for its unique ID:
$this->dispatch("map:update-cluster-data-{$clusterId}", \Kwasii\LivewireMapcn\Support\GeoJSON::fromArray($filteredData) );