{"id":59753,"date":"2026-04-15T09:45:00","date_gmt":"2026-04-15T16:45:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/dotnet\/?p=59753"},"modified":"2026-04-15T09:48:58","modified_gmt":"2026-04-15T16:48:58","slug":"pin-clustering-in-dotnet-maui-maps","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/pin-clustering-in-dotnet-maui-maps\/","title":{"rendered":"Pin Clustering in .NET MAUI Maps"},"content":{"rendered":"<p>If you&#8217;ve ever loaded a map with dozens \u2014 or hundreds \u2014 of pins, you know the result: an overlapping mess that&#8217;s impossible to interact with. Starting in <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/dotnet-11-preview-3\/\">.NET MAUI 11 Preview 3<\/a>, the Map control supports pin clustering out of the box on Android and iOS\/Mac Catalyst.<\/p>\n<h2>What is pin clustering?<\/h2>\n<p>Pin clustering automatically groups nearby pins into a single cluster marker when zoomed out. As you zoom in, clusters expand to reveal individual pins. This is a long-requested feature (<a href=\"https:\/\/github.com\/dotnet\/maui\/issues\/11811\">#11811<\/a>) and one that every map-heavy app needs.<\/p>\n<h2>Enable clustering<\/h2>\n<p>A single property is all it takes:<\/p>\n<pre><code class=\"language-xml\">&lt;maps:Map IsClusteringEnabled=\"True\" \/&gt;<\/code><\/pre>\n<p>That&#8217;s it. Nearby pins are now grouped into clusters with a count badge showing how many pins are in each group.<\/p>\n<h2>Separate clustering groups<\/h2>\n<p>Not all pins are the same. You might want coffee shops to cluster independently from parks, or hotels separately from attractions. The <code>ClusteringIdentifier<\/code> property on <code>Pin<\/code> makes this possible:<\/p>\n<pre><code class=\"language-csharp\">map.Pins.Add(new Pin\r\n{\r\n    Label = \"Pike Place Coffee\",\r\n    Location = new Location(47.6097, -122.3331),\r\n    ClusteringIdentifier = \"coffee\"\r\n});\r\n\r\nmap.Pins.Add(new Pin\r\n{\r\n    Label = \"Occidental Square\",\r\n    Location = new Location(47.6064, -122.3325),\r\n    ClusteringIdentifier = \"parks\"\r\n});<\/code><\/pre>\n<p>Pins with the same identifier cluster together. Pins with different identifiers form independent clusters even when geographically close. Pins with no identifier share a default group.<\/p>\n<h2>Handle cluster taps<\/h2>\n<p>When a user taps a cluster, the <code>ClusterClicked<\/code> event fires with a <code>ClusterClickedEventArgs<\/code> that gives you access to the pins in the cluster:<\/p>\n<pre><code class=\"language-csharp\">map.ClusterClicked += async (sender, e) =&gt;\r\n{\r\n    string names = string.Join(\"\\n\", e.Pins.Select(p =&gt; p.Label));\r\n    await DisplayAlert(\r\n        $\"Cluster ({e.Pins.Count} pins)\",\r\n        names,\r\n        \"OK\");\r\n\r\n    \/\/ Suppress default zoom-to-cluster behavior:\r\n    \/\/ e.Handled = true;\r\n};<\/code><\/pre>\n<p>The event args include:<\/p>\n<ul>\n<li><strong><code>Pins<\/code><\/strong> \u2014 the pins in the cluster<\/li>\n<li><strong><code>Location<\/code><\/strong> \u2014 the geographic center of the cluster<\/li>\n<li><strong><code>Handled<\/code><\/strong> \u2014 set to <code>true<\/code> if you want to handle the tap yourself instead of the default zoom behavior<\/li>\n<\/ul>\n<h2>Platform notes<\/h2>\n<p>On <strong>Android<\/strong>, clustering uses a custom grid-based algorithm that recalculates when the zoom level changes. No external dependencies are required.<\/p>\n<p>On <strong>iOS and Mac Catalyst<\/strong>, clustering leverages the native <code>MKClusterAnnotation<\/code> support in MapKit, providing smooth, platform-native cluster animations.<\/p>\n<h2>Try it out<\/h2>\n<p>The <a href=\"https:\/\/github.com\/dotnet\/maui-samples\/tree\/main\/10.0\/UserInterface\/Views\/Map\/MapDemo\/WorkingWithMaps\">Maps sample in maui-samples<\/a> includes a new <strong>Clustering<\/strong> page that demonstrates pin clustering with multiple clustering groups and cluster tap handling.<\/p>\n<p>For the full API reference and additional examples, see the <a href=\"https:\/\/learn.microsoft.com\/dotnet\/maui\/user-interface\/controls\/map?view=net-maui-11.0#pins\">Maps documentation<\/a>.<\/p>\n<h2>Summary<\/h2>\n<p>Pin clustering brings a polished, production-ready experience to .NET MAUI Maps. Enable it with a single property, customize it with clustering identifiers, and handle taps with a straightforward event. We&#8217;re looking forward to seeing what you build with it.<\/p>\n<p>Get started by installing <a href=\"https:\/\/dotnet.microsoft.com\/download\/dotnet\/11.0\">.NET 11 Preview 3<\/a> and updating or installing the .NET MAUI workload.<\/p>\n<p>If you\u2019re on Windows using Visual Studio, we recommend installing the latest <a href=\"https:\/\/visualstudio.microsoft.com\/insiders\">Visual Studio 2026 Insiders<\/a>. You can also use Visual Studio Code and the <a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=ms-dotnettools.csdevkit\">C# Dev Kit<\/a> extension with .NET 11.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>.NET MAUI 11 adds pin clustering to the Map control, automatically grouping nearby pins into cluster markers. Learn how to enable clustering, create separate clustering groups, and handle cluster taps on Android and iOS.<\/p>\n","protected":false},"author":553,"featured_media":59915,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[685,7233],"tags":[7893,8133,7359,7731,7368],"class_list":["post-59753","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-maui","tag-dotnet-11","tag-clustering","tag-controls","tag-maps","tag-mobile"],"acf":[],"blog_post_summary":"<p>.NET MAUI 11 adds pin clustering to the Map control, automatically grouping nearby pins into cluster markers. Learn how to enable clustering, create separate clustering groups, and handle cluster taps on Android and iOS.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/59753","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/553"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=59753"}],"version-history":[{"count":2,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/59753\/revisions"}],"predecessor-version":[{"id":59914,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/59753\/revisions\/59914"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/59915"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=59753"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=59753"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=59753"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}