Skip to content

Add BadgeText, BadgeColor, and BadgeTextColor support to ToolbarItem#34669

Open
jfversluis wants to merge 9 commits intonet11.0from
feature/toolbar-badge-support
Open

Add BadgeText, BadgeColor, and BadgeTextColor support to ToolbarItem#34669
jfversluis wants to merge 9 commits intonet11.0from
feature/toolbar-badge-support

Conversation

@jfversluis
Copy link
Copy Markdown
Member

@jfversluis jfversluis commented Mar 26, 2026

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!

Description

Adds BadgeText, BadgeColor, and BadgeTextColor properties to ToolbarItem, enabling badge notifications on toolbar items across all platforms.

Fixes #8305 (partial - ToolbarItem badges; Shell tab badges handled in #34659)

API

// Set a numeric badge
toolbarItem.BadgeText = "5";

// Set a text badge  
toolbarItem.BadgeText = "New";

// Dot indicator (small badge with no text)
toolbarItem.BadgeText = "";

// Custom badge colors
toolbarItem.BadgeColor = Colors.Blue;
toolbarItem.BadgeTextColor = Colors.White;

// Clear badge
toolbarItem.BadgeText = null;

Badge Text Semantics

Value Behavior
null No badge (hidden)
"" (empty string) Dot indicator
"3" Numeric count badge
"New" Text badge

Platform Support

Platform Implementation Notes
Android BadgeDrawable via Material Components Full text + color support. ClearNumber() for dot mode. Uses BadgeUtils.attachBadgeDrawable() with race condition guard.
iOS 26+ Native UIBarButtonItem.badge API Numeric and text badges. Create(0) for dot. Requires iOS 26+, no-op on earlier versions.
macOS (Catalyst 26+) Same as iOS Shares iOS implementation via Catalyst.
Windows InfoBadge overlay on AppBarButton Numeric values show count; non-numeric text and empty string show dot indicator.

Properties

Property Type Description
BadgeText string? Text/number on badge. null = hidden, "" = dot, non-empty = text/count.
BadgeColor Color? Background color. null = platform default.
BadgeTextColor Color? Foreground (text) color. null = platform default (typically white).

Changes

  • ToolbarItem.cs — Added BadgeText, BadgeColor, BadgeTextColor bindable properties with XML docs
  • ToolbarExtensions.cs (Android) — Badge rendering via BadgeDrawable with ConcurrentDictionary tracking, stale-update guard, and cleanup in DisposeMenuItems
  • ToolbarItemExtensions.cs (iOS) — iOS 26+ native badge API with platform version check
  • Toolbar.Windows.csInfoBadge overlay on AppBarButton content grid (both icon and text-only items)
  • 27 unit tests in ToolbarItemBadgeTests.cs
  • 4 UI tests (HostApp page + NUnit test with screenshots)
  • Sample gallery page ToolbarBadgePage.cs
  • All 7 PublicAPI.Unshipped.txt files updated

jfversluis and others added 2 commits March 26, 2026 11:52
Extends badge support from Shell bottom tabs (PR #34659) to ToolbarItems.
Uses native platform APIs: Android BadgeUtils/BadgeDrawable, iOS 26+
UIBarButtonItem.badge, and Windows InfoBadge overlay.

Includes 17 unit tests, UI test page, and sample gallery page.

Fixes #8305

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Replace deprecated Frame with Border control
- Add System and Microsoft.Maui usings
- Fix nullable Color? parameter in SetBadgeColor

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 26, 2026 13:12
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 26, 2026

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 34669

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 34669"

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds cross-platform badge support to ToolbarItem via new BadgeText/BadgeColor bindable properties, with platform renderers and accompanying tests/samples.

Changes:

  • Introduces ToolbarItem.BadgeText and ToolbarItem.BadgeColor plus PublicAPI updates.
  • Implements badge rendering on Android (Material BadgeDrawable), iOS/MacCatalyst (native UIBarButtonItem badge), and Windows (InfoBadge overlay).
  • Adds unit tests, UI tests (HostApp + Appium), and a sample gallery page demonstrating toolbar badges.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 14 comments.

Show a summary per file
File Description
src/Controls/src/Core/Toolbar/ToolbarItem.cs Adds BadgeText/BadgeColor bindable properties and XML docs.
src/Controls/src/Core/Platform/Android/Extensions/ToolbarExtensions.cs Renders badges with BadgeDrawable, includes lifecycle tracking and async attachment logic.
src/Controls/src/Core/Compatibility/iOS/Extensions/ToolbarItemExtensions.cs Updates iOS primary toolbar item wrapper to apply native badge when supported.
src/Controls/src/Core/Toolbar/Toolbar.Windows.cs Adds InfoBadge overlay and updates it on ToolbarItem property changes.
src/Controls/src/Core/PublicAPI/*/PublicAPI.Unshipped.txt Adds unshipped PublicAPI entries for the new ToolbarItem badge members across TFMs.
src/Controls/tests/Core.UnitTests/ToolbarItemBadgeTests.cs Unit tests for default values, binding, and property-changed behavior.
src/Controls/tests/TestCases.HostApp/Issues/Issue8305_Toolbar.cs HostApp page used by UITests to exercise badge scenarios.
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue8305_Toolbar.cs Appium UI tests + screenshots for toolbar badge scenarios.
src/Controls/samples/Controls.Sample/ViewModels/CoreViewModel.cs Registers the new sample page in the gallery navigation.
src/Controls/samples/Controls.Sample/Pages/Core/ToolbarBadgePage.cs Sample page demonstrating numeric/text badges and color changes.
src/Core/maps/src/PublicAPI/net/PublicAPI.Unshipped.txt Removes duplicate/unannotated entries for IMap.ShowInfoWindow/HideInfoWindow.

The test file was missing NUnit.Framework, UITest.Appium, and
UITest.Core usings, and used incorrect namespace causing build
failures in Controls.TestCases.Mac.Tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@AlleSchonWeg
Copy link
Copy Markdown
Contributor

Hi @jfversluis
i have implemented a toolbaritem badge in my app. You have added BadgeColor (BackgroundColor) and BadgeText. Good start.
Also important is:
TextColor --> UIBarButtonItemBadge.ForegroundColor and BadgeDrawable.BadgeTextColor
IsVisible --> UIBarButtonItem.Badge = null and BadgeDrawable.SetVisible()

Nice to have:
BadgeTextFont

…text-only items, Android cleanup

- Add BadgeTextColor property to ToolbarItem for foreground text color customization
  - Android: BadgeDrawable.BadgeTextColor
  - iOS/MacCatalyst 26+: UIBarButtonItemBadge.ForegroundColor
  - Windows: InfoBadge.Foreground brush
- Add retryTimeout to all VerifyScreenshot() calls for async Android badge rendering
- Fix Windows text-only toolbar items: wrap in Grid+InfoBadge overlay
- Add ReferenceEquals guard in Android toolbar.Post() callback for recycled menu items
- Clean up all badge drawables in DisposeMenuItems
- Add 7 unit tests for BadgeTextColor (24 total)
- Update all 7 PublicAPI.Unshipped.txt files
- Add Badge Text Color section to sample gallery page

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jfversluis
Copy link
Copy Markdown
Member Author

Thanks for the feedback @AlleSchonWeg! Great to hear you've implemented toolbar badges in your app.

BadgeTextColor — Implemented in 374ae80! New BadgeTextColor property maps to:

  • Android: BadgeDrawable.BadgeTextColor
  • iOS/MacCatalyst 26+: UIBarButtonItemBadge.ForegroundColor
  • Windows: InfoBadge.Foreground

IsVisible — Setting BadgeText = null already clears the badge completely (which effectively hides it). Adding a separate IsVisible property would add complexity without significant benefit since the same result is achieved by toggling BadgeText. If there's a specific use case where you need to preserve the text while hiding the badge, we can revisit this.

BadgeTextFont — This is tricky as platform support varies significantly. Android's BadgeDrawable doesn't expose font customization, and iOS's UIBarButtonItemBadge is similarly limited. We'll leave this out for now but could add it in a future iteration if platform APIs evolve.

@AlleSchonWeg
Copy link
Copy Markdown
Contributor

AlleSchonWeg commented Mar 26, 2026

Thanks for implementing my suggestion @jfversluis

IsVisible — Setting BadgeText = null already clears the badge completely (which effectively hides it). Adding a separate IsVisible property would add complexity without significant benefit since the same result is achieved by toggling BadgeText. If there's a specific use case where you need to preserve the text while hiding the badge, we can revisit this.

I find setting BadgeText = null not intuitive. and the developer must know that it works this way. Almost every UI-Control has a IsVisible property. As a dev i would check this property first.
Setting an empty/null text i could also create a indicator on a toolbaritem. Many apps have a small red point on a toolbar item which indicates "that there is something". Sometimes a new setting or something thats needs attention. (https://m2.material.io/develop/android/supporting/badge)

As i implemented my badge i observed a crazy behaviour on android. I added the badge on a toolbar item on one page and on another page(s) the badge also appeared. But only the badge. The icon, color etc. was correct. I don't know if i had done something wrong. Perhaps some internal caching or whatever. My setup was a TabbedPage with 4 tabs. Every tab had a NavigationPage and on the first Root ContentPage i had the item with badge plus another item without badge. The other Root ContentPages had also toolbar items but without badges. Perhaps this info can help with your implementation.

@jfversluis
Copy link
Copy Markdown
Member Author

/azp run maui-pr-uitests

Change BadgeText semantics: null = no badge, empty string = dot indicator,
non-empty string = text/count badge. Previously both null and empty string
hid the badge.

Platform implementations:
- Android: ClearNumber() on BadgeDrawable for dot mode
- iOS: UIBarButtonItemBadge.Create(0) for dot indicator
- Windows: Value = -1 for empty string (dot indicator)

Added 3 unit tests for dot badge behavior.
Updated XML docs to document null vs empty string semantics.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jfversluis
Copy link
Copy Markdown
Member Author

Implemented dot badge support! You can now set BadgeText = "" (empty string) to show a small dot indicator badge without any text. The semantics are:

  • null → no badge (hidden)
  • "" (empty string) → dot indicator
  • "3" → count badge
  • "New" → text badge

Platform-specific behavior:

  • Android: Uses BadgeDrawable.ClearNumber() which displays the native dot mode
  • iOS/MacCatalyst: Uses UIBarButtonItemBadge.Create(0) for a minimal dot
  • Windows: Uses InfoBadge.Value = -1 which renders as a dot

This applies to both PRs (#34659 Shell tabs and #34669 ToolbarItems).

Commit: 1d1549c (toolbar) and 39c8d64 (shell)

@jfversluis jfversluis changed the title Add BadgeText and BadgeColor support to ToolbarItem Add BadgeText, BadgeColor, and BadgeTextColor support to ToolbarItem Mar 26, 2026
@jfversluis
Copy link
Copy Markdown
Member Author

/azp run maui-pr

@jfversluis
Copy link
Copy Markdown
Member Author

/azp run maui-pr-uitests

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

1 similar comment
@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

@bronteq
Copy link
Copy Markdown

bronteq commented Mar 27, 2026

also this issue #23802 will be solved by this pr

Remove duplicate entries that caused RS0025 build errors.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jfversluis
Copy link
Copy Markdown
Member Author

/azp run maui-pr

@jfversluis
Copy link
Copy Markdown
Member Author

/azp run maui-pr-uitests

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

1 similar comment
@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

- Remove WaitForElement for ToolbarItem AutomationId (not accessible via
  Appium on WinUI) — wait for page StatusLabel instead
- Add Windows reference screenshots for ToolbarItemBadgesClear and
  ToolbarItemBadgeColorChanges tests

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jfversluis
Copy link
Copy Markdown
Member Author

/azp run maui-pr-uitests

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

@jfversluis
Copy link
Copy Markdown
Member Author

/azp run maui-pr

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

jfversluis and others added 2 commits March 27, 2026 17:18
- Add 3 iOS (ios-26) reference screenshots: ToolbarItemBadgesDisplay,
  ToolbarItemBadgesClear, ToolbarItemBadgeColorChanges
- Add 3 Android reference screenshots for the same tests
- Generated from CI build 1355044 snapshot artifacts

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jfversluis
Copy link
Copy Markdown
Member Author

/azp run maui-pr-uitests

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants