Skip to content

Comments

[iOS 26] Fix for Shell ForegroundColor not applied to ToolbarItems#34085

Open
SyedAbdulAzeemSF4852 wants to merge 4 commits intodotnet:mainfrom
SyedAbdulAzeemSF4852:fix-ios26-toolbaritem-color
Open

[iOS 26] Fix for Shell ForegroundColor not applied to ToolbarItems#34085
SyedAbdulAzeemSF4852 wants to merge 4 commits intodotnet:mainfrom
SyedAbdulAzeemSF4852:fix-ios26-toolbaritem-color

Conversation

@SyedAbdulAzeemSF4852
Copy link
Contributor

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!

Issue Details

  • On iOS 26, setting Shell.ForegroundColor (either at the Shell level or Page level) no longer applies the specified color to ToolbarItems.
  • The toolbar items remain in the default system tint color instead of respecting the configured foreground color.

Root Cause

  • On iOS 26, Apple's LiquidGlass redesign changed how UINavigationBar.TintColor propagates to bar button items — it is no longer automatically inherited.

Description of Change

  • Added UpdateRightBarButtonItemTintColors() method in ShellPageRendererTracker.cs to explicitly set the TintColor of right bar button items to the Shell's foreground color for iOS 26+ and Mac Catalyst 26+. This ensures toolbar items correctly reflect the intended color.
  • Updated property change handlers (HandleShellPropertyChanged, OnPagePropertyChanged) to call UpdateRightBarButtonItemTintColors() when relevant properties change, guaranteeing color updates are applied when needed.

Issues Fixed

Fixes #34083

Validated the behaviour in the following platforms

  • Windows
  • Android
  • iOS
  • Mac

Output

Before After

@dotnet-policy-service dotnet-policy-service bot added the community ✨ Community Contribution label Feb 17, 2026
@dotnet-policy-service
Copy link
Contributor

Hey there @@SyedAbdulAzeemSF4852! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed.

@dotnet-policy-service dotnet-policy-service bot added the partner/syncfusion Issues / PR's with Syncfusion collaboration label Feb 17, 2026
@sheiksyedm sheiksyedm marked this pull request as ready for review February 18, 2026 11:15
Copilot AI review requested due to automatic review settings February 18, 2026 11:15
@sheiksyedm
Copy link
Contributor

/azp run maui-pr-uitests , maui-pr-devicetests

@azure-pipelines
Copy link

Azure Pipelines successfully started running 2 pipeline(s).

Copy link
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

This pull request fixes an iOS 26-specific issue where Shell.ForegroundColor is not applied to toolbar items due to Apple's LiquidGlass redesign changes. In iOS 26+, UINavigationBar.TintColor no longer automatically propagates to bar button items, requiring explicit TintColor setting on each item.

Changes:

  • Added UpdateRightBarButtonItemTintColors() method to explicitly set TintColor on right bar button items for iOS 26+ and MacCatalyst 26+
  • Updated property change handlers (HandleShellPropertyChanged, OnPagePropertyChanged) to call the new method when ForegroundColor changes
  • Added UI test (Issue34083) with screenshot verification to validate the fix

Reviewed changes

Copilot reviewed 3 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
ShellPageRendererTracker.cs Added iOS 26+ workaround to explicitly set TintColor on right bar button items when Shell.ForegroundColor changes
Issue34083.cs (HostApp) Test page demonstrating Shell with ForegroundColor and toolbar item
Issue34083.cs (Tests) UI test with screenshot verification for toolbar item color
VerifyShellForegroundColorIsAppliedToToolbarItems.png (ios) Baseline screenshot for iOS < 26
VerifyShellForegroundColorIsAppliedToToolbarItems.png (ios-26) Baseline screenshot for iOS 26+
Comments suppressed due to low confidence (1)

src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellPageRendererTracker.cs:612

  • The fix only applies TintColor to right bar button items (toolbar items), but the left bar button item (back button/flyout icon) may also be affected by the iOS 26 LiquidGlass change. The UpdateLeftToolbarItems method creates a UIBarButtonItem at line 575-576, but its TintColor is not explicitly set for iOS 26+.

Consider also updating the left bar button item's TintColor in UpdateLeftToolbarItems when iOS 26+ is detected, similar to how UpdateRightBarButtonItemTintColors handles right bar button items. The left bar button item is set in the callback at lines 575-576, so you would need to apply the TintColor there:

NavigationItem.LeftBarButtonItem =
    new UIBarButtonItem(icon, UIBarButtonItemStyle.Plain, (s, e) => LeftBarButtonItemHandler(ViewController, IsRootPage)) { Enabled = enabled };

// Add for iOS 26+
if (OperatingSystem.IsIOSVersionAtLeast(26) || OperatingSystem.IsMacCatalystVersionAtLeast(26))
{
    var foregroundColor = _context?.Shell?.CurrentPage?.GetValue(Shell.ForegroundColorProperty) ??
                        _context?.Shell?.GetValue(Shell.ForegroundColorProperty);
    if (foregroundColor is Graphics.Color shellForegroundColor)
    {
        NavigationItem.LeftBarButtonItem.TintColor = shellForegroundColor.ToPlatform();
    }
}
		void UpdateLeftToolbarItems()
		{
			var shell = _context?.Shell;
			var mauiContext = MauiContext;

			if (shell is null || NavigationItem is null || mauiContext is null)
			{
				return;
			}

			var behavior = BackButtonBehavior;

			var image = behavior.GetPropertyIfSet<ImageSource?>(BackButtonBehavior.IconOverrideProperty, null);
			var enabled = behavior.GetPropertyIfSet(BackButtonBehavior.IsEnabledProperty, true);
			var text = behavior.GetPropertyIfSet<string?>(BackButtonBehavior.TextOverrideProperty, null);
			var command = behavior.GetPropertyIfSet<object?>(BackButtonBehavior.CommandProperty, null);
			var backButtonVisible = behavior.GetPropertyIfSet<bool>(BackButtonBehavior.IsVisibleProperty, true);

			if (String.IsNullOrWhiteSpace(text) && image == null)
			{
				//Add the FlyoutIcon only if the FlyoutBehavior is Flyout
				if (_flyoutBehavior == FlyoutBehavior.Flyout)
				{
					image = shell.FlyoutIcon;
				}
			}

			if (!IsRootPage)
			{
				NavigationItem.HidesBackButton = !backButtonVisible;
				image = backButtonVisible ? image : null;
			}

			image.LoadImage(mauiContext, result =>
			{
				if (ViewController is null)
					return;

				UIImage? icon = null;

				if (image is not null)
				{
					icon = result?.Value;

					var foregroundColor = _context?.Shell.CurrentPage?.GetValue(Shell.ForegroundColorProperty) ??
					_context?.Shell.GetValue(Shell.ForegroundColorProperty);

					if (foregroundColor is null)
					{
						icon = icon?.ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal);
					}

					var originalImageSize = icon?.Size ?? CGSize.Empty;

					// The largest height you can use for navigation bar icons in iOS.
					// Per Apple's Human Interface Guidelines, the navigation bar height is 44 points,
					// so using the full height ensures maximum visual clarity and maintains consistency
					// with iOS design standards. This allows icons to utilize the entire available
					// vertical space within the navigation bar container.
					var defaultIconHeight = 44f;
					var buffer = 0.1;
					// We only check height because the navigation bar constrains vertical space (44pt height),
					// but allows horizontal flexibility. Width can vary based on icon design and content,
					// while height must fit within the fixed navigation bar bounds to avoid clipping.

					// if the image is bigger than the default available size, resize it

					if (icon is not null && originalImageSize.Height - defaultIconHeight > buffer)
					{
						if (image is not FontImageSource fontImageSource || !fontImageSource.IsSet(FontImageSource.SizeProperty))
						{
							icon = icon.ResizeImageSource(originalImageSize.Width, defaultIconHeight, originalImageSize);
						}
					}
				}
				else if (String.IsNullOrWhiteSpace(text) && IsRootPage && _flyoutBehavior == FlyoutBehavior.Flyout)
				{
					icon = DrawHamburger();
				}

				if (icon != null)
				{
					NavigationItem.LeftBarButtonItem =
						new UIBarButtonItem(icon, UIBarButtonItemStyle.Plain, (s, e) => LeftBarButtonItemHandler(ViewController, IsRootPage)) { Enabled = enabled };
				}
				else
				{
					NavigationItem.LeftBarButtonItem = null;
					UpdateBackButtonTitle();
				}

				if (NavigationItem.LeftBarButtonItem != null)
				{
					if (String.IsNullOrWhiteSpace(image?.AutomationId))
					{
						if (IsRootPage)
						{
							NavigationItem.LeftBarButtonItem.AccessibilityIdentifier = "OK";
							NavigationItem.LeftBarButtonItem.AccessibilityLabel = "Menu";
						}
						else
							NavigationItem.LeftBarButtonItem.AccessibilityIdentifier = "Back";
					}
					else
					{
						NavigationItem.LeftBarButtonItem.AccessibilityIdentifier = image.AutomationId;
					}

					if (image != null)
					{
#pragma warning disable CS0618 // Type or member is obsolete
						NavigationItem.LeftBarButtonItem.SetAccessibilityHint(image);
						NavigationItem.LeftBarButtonItem.SetAccessibilityLabel(image);
#pragma warning restore CS0618 // Type or member is obsolete
					}
				}
			});

			UpdateBackButtonTitle();
		}

Comment on lines +470 to +488
if (!(OperatingSystem.IsIOSVersionAtLeast(26) || OperatingSystem.IsMacCatalystVersionAtLeast(26)))
{
return;
}

if (NavigationItem?.RightBarButtonItems is not { Length: > 0 } rightItems)
{
return;
}

var foregroundColor = _context?.Shell?.CurrentPage?.GetValue(Shell.ForegroundColorProperty) ??
_context?.Shell?.GetValue(Shell.ForegroundColorProperty);

if (foregroundColor is Graphics.Color shellForegroundColor)
{
var platformColor = shellForegroundColor.ToPlatform();
foreach (var item in rightItems)
{
item.TintColor = platformColor;
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

The version check logic is inverted. The condition !(OperatingSystem.IsIOSVersionAtLeast(26) || OperatingSystem.IsMacCatalystVersionAtLeast(26)) returns early when the version is LESS than 26, meaning the TintColor update only happens on iOS 26+. This is correct based on the PR description.

However, consider using a positive condition for better readability:

if (OperatingSystem.IsIOSVersionAtLeast(26) || OperatingSystem.IsMacCatalystVersionAtLeast(26))
{
    // Update TintColor for iOS 26+ only
    if (NavigationItem?.RightBarButtonItems is not { Length: > 0 } rightItems)
    {
        return;
    }
    // ... rest of the logic
}

This makes it immediately clear that the code executes FOR iOS 26+, not AGAINST it.

Suggested change
if (!(OperatingSystem.IsIOSVersionAtLeast(26) || OperatingSystem.IsMacCatalystVersionAtLeast(26)))
{
return;
}
if (NavigationItem?.RightBarButtonItems is not { Length: > 0 } rightItems)
{
return;
}
var foregroundColor = _context?.Shell?.CurrentPage?.GetValue(Shell.ForegroundColorProperty) ??
_context?.Shell?.GetValue(Shell.ForegroundColorProperty);
if (foregroundColor is Graphics.Color shellForegroundColor)
{
var platformColor = shellForegroundColor.ToPlatform();
foreach (var item in rightItems)
{
item.TintColor = platformColor;
if (OperatingSystem.IsIOSVersionAtLeast(26) || OperatingSystem.IsMacCatalystVersionAtLeast(26))
{
if (NavigationItem?.RightBarButtonItems is not { Length: > 0 } rightItems)
{
return;
}
var foregroundColor = _context?.Shell?.CurrentPage?.GetValue(Shell.ForegroundColorProperty) ??
_context?.Shell?.GetValue(Shell.ForegroundColorProperty);
if (foregroundColor is Graphics.Color shellForegroundColor)
{
var platformColor = shellForegroundColor.ToPlatform();
foreach (var item in rightItems)
{
item.TintColor = platformColor;
}

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,24 @@
#if TEST_FAILS_ON_ANDROID && TEST_FAILS_ON_WINDOWS // Android Issue Link: https://github.com/dotnet/maui/issues/24676, Windows Issue Link: https://github.com/dotnet/maui/issues/34071
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

The test includes a preprocessor directive TEST_FAILS_ON_ANDROID && TEST_FAILS_ON_WINDOWS which disables the test on Android and Windows. The comment references two separate issues for Android and Windows failures.

However, this test should NOT fail on these platforms - it's testing iOS-specific behavior (the test page is marked PlatformAffected.iOS). The test should simply not run on Android/Windows.

Consider using a cleaner approach:

  • Remove the TEST_FAILS_ON_ANDROID && TEST_FAILS_ON_WINDOWS directive entirely
  • The test framework should automatically skip tests for platforms not affected based on the PlatformAffected.iOS attribute in the Issue attribute
  • If platform-specific test execution is needed, use #if IOS || MACCATALYST instead

Copilot uses AI. Check for mistakes.
@rmarinho
Copy link
Member

rmarinho commented Feb 18, 2026

🤖 AI Summary

📊 Expand Full Review
🔍 Pre-Flight — Context & Validation
📝 Review SessionUpdated the issue tracker ID, file name, and class name to align with the reported issue ID. Also added the baseline snapshot for iOS. · 6c05a8f

Issue: #34083 - [iOS26] Shell.ForegroundColor is not applied to ToolbarItems
PR: #34085 - [iOS 26] Fix for Shell ForegroundColor not applied to ToolbarItems
Author: SyedAbdulAzeemSF4852 (Syncfusion partner contributor)
Platforms Affected: iOS 26, MacCatalyst 26 (not Android/Windows)
Labels: platform/ios, area-controls-toolbar, version/iOS-26, community ✨, partner/syncfusion

Prior Agent Review

A prior agent review was found at commit 6c05a8f7f5f344c98e8d626d71d66493194a7dde (current HEAD). Key findings from prior review:

  • Gate failed — test snapshots appear to have been captured while the bug was present, causing tests to pass both with and without the fix
  • Missing TintColor = null reset case when ForegroundColor is cleared at runtime
  • Code readability concern (negated condition) — minor style only

Issue Summary

On iOS 26, Apple's LiquidGlass redesign changed how UINavigationBar.TintColor propagates to bar button items — it is no longer automatically inherited. As a result, Shell.ForegroundColor set at the Shell or Page level no longer applies the specified color to ToolbarItems on iOS 26+.

Root Cause

Apple changed the behavior of UINavigationBar.TintColor propagation in iOS 26 as part of the LiquidGlass redesign. Previously, setting TintColor on the navigation bar would automatically propagate to bar button items. Starting with iOS 26, this propagation no longer happens automatically.

Fix Description

Added UpdateRightBarButtonItemTintColors() method in ShellPageRendererTracker.cs that:

  • Only runs on iOS 26+ or MacCatalyst 26+
  • Explicitly iterates over NavigationItem.RightBarButtonItems and sets TintColor on each item
  • Reads ForegroundColor from CurrentPage first, then falls back to the Shell level
  • Called from UpdateToolbarItems(), HandleShellPropertyChanged, and OnPagePropertyChanged

Files Changed

Fix files:

  • src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellPageRendererTracker.cs (+32 lines)

Test files:

  • src/Controls/tests/TestCases.HostApp/Issues/Issue34083.cs (+32 lines, new)
  • src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue34083.cs (+24 lines, new)

Snapshot images:

  • src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/VerifyShellForegroundColorIsAppliedToToolbarItems.png (new)
  • src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/VerifyShellForegroundColorIsAppliedToToolbarItems.png (new)

Reviewer Comments

Copilot automated review flagged 2 issues:

File:Line Reviewer Says Status
ShellPageRendererTracker.cs:488 Suggest using positive condition instead of negated early return ⚠️ Minor style concern
Issue34083.cs:1 TEST_FAILS_ON_ANDROID && TEST_FAILS_ON_WINDOWS — suggest removing, but this IS the standard pattern for iOS-only tests ℹ️ Not an issue - standard codebase pattern

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #34085 Explicitly set TintColor on right bar button items for iOS 26+ in UpdateRightBarButtonItemTintColors() ⏳ PENDING (Gate) ShellPageRendererTracker.cs (+32) Original PR

🚦 Gate — Test Verification
📝 Review SessionUpdated the issue tracker ID, file name, and class name to align with the reported issue ID. Also added the baseline snapshot for iOS. · 6c05a8f

Result: ❌ FAILED
Platform: ios
Mode: Full Verification

Test Results

Check Expected Actual Result
Tests FAIL without fix FAIL PASS
Tests PASS with fix PASS PASS

Analysis

The Gate verification failed because the test passes both with and without the fix. The reference snapshot files (ios-26/VerifyShellForegroundColorIsAppliedToToolbarItems.png and ios/VerifyShellForegroundColorIsAppliedToToolbarItems.png) appear to have been captured while the bug was still present (showing the default system tint color, not purple).

When the fix is reverted, the UI matches the reference snapshot (buggy state = default color), causing the test to pass. This means the test does not effectively catch the regression.

Conclusion

⛔ Gate FAILED - The test snapshots were captured showing the buggy state (toolbar items with default system tint color, not purple). The snapshots need to be re-taken after the fix is applied and verified working (showing purple toolbar items).


🔧 Fix — Analysis & Comparison
📝 Review SessionUpdated the issue tracker ID, file name, and class name to align with the reported issue ID. Also added the baseline snapshot for iOS. · 6c05a8f

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #34085 Explicitly set TintColor on right bar button items for iOS 26+ in UpdateRightBarButtonItemTintColors() ❌ SKIPPED (Gate failed) ShellPageRendererTracker.cs (+32) Original PR

Exhausted: N/A - try-fix was skipped because Gate failed (tests pass regardless of fix state)

Reason for skip: The reference snapshots in the PR were captured while the bug was present (showing default system tint, not purple). Since VerifyScreenshot() compares against those snapshots, the test passes both with and without the fix. Running try-fix would produce unreliable/misleading results.

Selected Fix: PR's fix — The code approach is directionally correct (pending fixes noted in the Report). The fix correctly targets the iOS 26+ behavior change with the right method calls.


📋 Report — Final Recommendation
📝 Review SessionUpdated the issue tracker ID, file name, and class name to align with the reported issue ID. Also added the baseline snapshot for iOS. · 6c05a8f

⚠️ Final Recommendation: REQUEST CHANGES

Summary

PR #34085 addresses a real iOS 26 regression where Apple's LiquidGlass redesign broke UINavigationBar.TintColor automatic propagation to bar button items. The fix approach (explicitly setting TintColor per item for iOS 26+ and MacCatalyst 26+) is directionally correct. However, there are two issues that need to be addressed before merge:

  1. Critical: Test snapshots captured with bug present — Gate verification confirms tests pass both with and without the fix, meaning the reference snapshots show the buggy state (default tint, not purple). Tests provide false confidence.
  2. Functional: Missing TintColor reset when ForegroundColor is cleared at runtime — If a user sets then clears Shell.ForegroundColor, the toolbar items will retain the previously-set TintColor instead of reverting to the system default.

Root Cause

On iOS 26, Apple's LiquidGlass redesign changed how UINavigationBar.TintColor propagates to bar button items — it is no longer automatically inherited by UIBarButtonItem instances. Previously, MAUI relied on UIKit to propagate the navigation bar's TintColor to individual UIBarButtonItem instances. Starting with iOS 26, this propagation must be done explicitly by the app.


Code Review Findings

🔴 Test Snapshots Captured in Buggy State (High)

Files:

  • src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/VerifyShellForegroundColorIsAppliedToToolbarItems.png
  • src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/VerifyShellForegroundColorIsAppliedToToolbarItems.png

Problem: Gate verification confirmed tests pass both WITH and WITHOUT the fix applied. The reference snapshots show the toolbar items in the default system tint color (the buggy state), not in purple. As a result, VerifyScreenshot() passes whether or not the toolbar items are purple — the test doesn't verify the fix is working.

Fix required: Delete the existing snapshots and re-run the test suite on iOS 26 with the fix confirmed working (toolbar items must appear purple/in the configured ForegroundColor). The new snapshots captured from a passing state will serve as the correct baseline.


🔴 Missing TintColor Reset When ForegroundColor is Cleared (Medium)

File: src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellPageRendererTracker.cs

Problem: UpdateRightBarButtonItemTintColors() only sets TintColor when foregroundColor is a Color. If the user removes/unsets ForegroundColor (sets to null), the TintColor on existing bar button items is never reset — the previous color will persist permanently.

// Current code - missing the null/reset case
if (foregroundColor is Graphics.Color shellForegroundColor)
{
    var platformColor = shellForegroundColor.ToPlatform();
    foreach (var item in rightItems)
    {
        item.TintColor = platformColor;
    }
}
// Missing: else branch to reset to system default

Fix required:

if (foregroundColor is Graphics.Color shellForegroundColor)
{
    var platformColor = shellForegroundColor.ToPlatform();
    foreach (var item in rightItems)
    {
        item.TintColor = platformColor;
    }
}
else
{
    foreach (var item in rightItems)
    {
        item.TintColor = null; // Reset to system default
    }
}

🟡 Code Readability: Negative Condition (Low)

File: ShellPageRendererTracker.cs, line ~470

The negated early-return condition makes intent slightly less clear:

// Current
if (!(OperatingSystem.IsIOSVersionAtLeast(26) || OperatingSystem.IsMacCatalystVersionAtLeast(26)))
{
    return;
}

Consider using a positive guard block for readability. Minor style concern only — functionally correct as-is.


✅ Looks Good

  • iOS 26+ version guard is correct — early return on pre-26 ensures no behavior change for older iOS versions
  • Property change hooks are comprehensiveUpdateRightBarButtonItemTintColors() is called from UpdateToolbarItems(), HandleShellPropertyChanged, and OnPagePropertyChanged
  • ForegroundColor fallback chain is correct — checks CurrentPage first, then falls back to Shell level (consistent with existing UpdateLeftToolbarItems() pattern)
  • MacCatalyst 26+ included — correctly applies to both iOS 26+ and MacCatalyst 26+
  • TEST_FAILS_ON_ANDROID && TEST_FAILS_ON_WINDOWS — this IS the correct standard pattern for iOS-only tests in this codebase (10+ existing tests use it). Automated reviewer concern is incorrect.
  • PR title and description are accurate and include the required NOTE block.

Issues to Address

Issue Impact Action Required
Test snapshots captured in buggy state 🔴 High Delete snapshots, re-run tests on iOS 26 with fix working to capture correct baseline
Missing TintColor reset for null ForegroundColor 🟡 Medium Add else branch resetting item.TintColor = null
Negative condition readability 🟡 Low Optional: refactor to positive guard block

📋 Expand PR Finalization Review
Title: ✅ Good

Current: [iOS 26] Fix for Shell ForegroundColor not applied to ToolbarItems

Description: ✅ Good

Description needs updates. See details below.

✨ Suggested PR Description

[!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!

Issue Details

  • On iOS 26 and Mac Catalyst 26+, setting Shell.ForegroundColor (either at the Shell level or Page level) no longer applies the specified color to ToolbarItems.
  • The toolbar items remain in the default system tint color instead of respecting the configured foreground color.

Root Cause

On iOS 26, Apple's LiquidGlass redesign changed how UINavigationBar.TintColor propagates to bar button items — it is no longer automatically inherited by UIBarButtonItem instances.

Description of Change

  • Added UpdateRightBarButtonItemTintColors() method in ShellPageRendererTracker.cs to explicitly set TintColor of right bar button items to the Shell's foreground color for iOS 26+ and Mac Catalyst 26+. This ensures toolbar items correctly reflect the intended color.
  • Updated property change handlers (HandleShellPropertyChanged, OnPagePropertyChanged) to call UpdateRightBarButtonItemTintColors() when relevant properties change, guaranteeing color updates are applied on dynamic property changes.
  • Called UpdateRightBarButtonItemTintColors() from UpdateToolbarItems() to apply the color on initial render.

Issues Fixed

Fixes #34083

Validated the behaviour in the following platforms

  • Windows
  • Android
  • iOS
  • Mac

Output

Before After
Code Review: ✅ Passed

PR #34085 Code Review

Code Review Findings

🟡 Medium Issue

Missing TintColor Reset When ForegroundColor Is Cleared

  • File: src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellPageRendererTracker.cs
  • Method: UpdateRightBarButtonItemTintColors()
  • Problem: The method only sets TintColor when a non-null Shell.ForegroundColor is found. If a user sets Shell.ForegroundColor and later clears it (sets to null/unset), the old TintColor will remain on the bar button items indefinitely. The items won't revert to the system-default tint color.

Current code:

if (foregroundColor is Graphics.Color shellForegroundColor)
{
    var platformColor = shellForegroundColor.ToPlatform();
    foreach (var item in rightItems)
    {
        item.TintColor = platformColor;
    }
}
// No else: TintColor stays at old value if foregroundColor is null

Recommendation: Add an else branch to reset to null (system default):

if (foregroundColor is Graphics.Color shellForegroundColor)
{
    var platformColor = shellForegroundColor.ToPlatform();
    foreach (var item in rightItems)
    {
        item.TintColor = platformColor;
    }
}
else
{
    foreach (var item in rightItems)
    {
        item.TintColor = null; // Reset to system default
    }
}

🟡 Minor Issue

Title Omits Mac Catalyst Coverage

  • Problem: The PR title [iOS 26] does not mention Mac Catalyst 26+, even though the code explicitly includes OperatingSystem.IsMacCatalystVersionAtLeast(26) in the version guard.
  • Recommendation: Change title to [iOS/Mac Catalyst 26] Fix Shell.ForegroundColor not applied to ToolbarItems

🔵 Trivial Issues

Missing trailing newlines in test files

Both new test files are missing a trailing newline (\ No newline at end of file):

  • src/Controls/tests/TestCases.HostApp/Issues/Issue34083.cs
  • src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue34083.cs

These should end with a newline per standard code style.


✅ Looks Good

  • Version guard is correct: OperatingSystem.IsIOSVersionAtLeast(26) || OperatingSystem.IsMacCatalystVersionAtLeast(26) — properly targets only the affected OS versions.
  • Color lookup precedence is correct: CurrentPage foreground color checked first, then falls back to Shell level — this mirrors how the existing Shell theming logic works.
  • All relevant call sites updated: UpdateToolbarItems(), HandleShellPropertyChanged(), and OnPagePropertyChanged() all call UpdateRightBarButtonItemTintColors(), ensuring color is applied on initial render and on dynamic property changes.
  • Snapshot baseline provided: Two snapshot files added for ios/ and ios-26/, ensuring the test has baseline images for both OS versions.
  • Test guards are correct: #if TEST_FAILS_ON_ANDROID && TEST_FAILS_ON_WINDOWS correctly limits the test to iOS and Mac Catalyst, since this is an iOS-specific behavior change. The PlatformAffected.iOS attribute on the HostApp issue page is also consistent.
  • No unnecessary scope change: New method is private (no access modifier) — not exposing this workaround as overridable API is appropriate given its narrow iOS 26-specific nature.

@rmarinho rmarinho added s/agent-changes-requested AI agent recommends changes - found a better alternative or issues s/agent-gate-failed AI could not verify tests catch the bug s/agent-fix-lose AI could not beat the PR fix - PR is the best among all candidates s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) labels Feb 18, 2026
@kubaflo kubaflo added s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates and removed s/agent-fix-lose AI could not beat the PR fix - PR is the best among all candidates labels Feb 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-controls-toolbar ToolBar community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration platform/ios s/agent-changes-requested AI agent recommends changes - found a better alternative or issues s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-gate-failed AI could not verify tests catch the bug s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) version/iOS-26

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[iOS26] Shell.ForegroundColor is not applied to ToolbarItems

5 participants