Skip to content

[iOS And Windows] Fix Entry IsPassword ignored when Keyboard is set to Password - #36677

Merged
kubaflo merged 1 commit into
dotnet:inflight/currentfrom
SyedAbdulAzeemSF4852:fix-35650
Jul 27, 2026
Merged

[iOS And Windows] Fix Entry IsPassword ignored when Keyboard is set to Password#36677
kubaflo merged 1 commit into
dotnet:inflight/currentfrom
SyedAbdulAzeemSF4852:fix-35650

Conversation

@SyedAbdulAzeemSF4852

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

  • An Entry with Keyboard="Password" always renders text as masked, ignoring IsPassword=false. Setting IsPassword=false has no effect on iOS (initial load) and Windows (initial load and runtime toggle) when Keyboard="Password" is set.

Root Cause

  • The MapIsPassword mapper runs before MapKeyboard in EntryHandler.cs on initial setup, so Keyboard.Password hardcodes masking behavior in ApplyKeyboard (iOS: SetSecureTextEntry(true)) and via an InputScope callback (Windows: OnInputScopePropertyChanged), both of which run after MapIsPassword and silently overwrite IsPassword=false.

Description of Change

  • iOS: Removed the hardcoded SetSecureTextEntry(true) from the Keyboard.Password branch in KeyboardExtensions.cs. SecureTextEntry is now set exclusively by TextFieldExtensions.UpdateIsPassword, respecting the actual IsPassword value.
  • Windows: Removed the OnInputScopePropertyChanged callback from MauiPasswordTextBox that automatically forced IsPassword=true whenever InputScope changed to Password, allowing developers to set IsPassword=false even when Keyboard=Password is used.

Note: The Android fix for the same issue is tracked separately in PR #36280.

Issues Fixed

Fixes #35650

Validated the behaviour in the following platforms

  • Windows
  • Android
  • iOS
  • Mac

Output

Platform Before After
iOS
iOS_Before.mov
iOS_After.mov
Windows
Windows_Before.mp4
Windows_After.mp4

@github-actions

Copy link
Copy Markdown
Contributor

🚀 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 -- 36677

Or

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

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service dotnet-policy-service Bot added the community ✨ Community Contribution label Jul 20, 2026
@dotnet-policy-service

Copy link
Copy Markdown
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 Jul 20, 2026
@SyedAbdulAzeemSF4852 SyedAbdulAzeemSF4852 changed the title [WIP][iOS And Windows] Fix Entry IsPassword ignored when Keyboard is set to Password [iOS And Windows] Fix Entry IsPassword ignored when Keyboard is set to Password Jul 21, 2026
@vishnumenon2684

Copy link
Copy Markdown
Contributor

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

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 2 pipeline(s).

@kubaflo

This comment has been minimized.

@github-actions github-actions Bot added the s/agent-review-in-progress AI review is currently running for this PR label Jul 21, 2026
@sheiksyedm

Copy link
Copy Markdown
Contributor

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

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 2 pipeline(s).

@kubaflo

This comment has been minimized.

@github-actions github-actions Bot added s/agent-review-in-progress AI review is currently running for this PR and removed s/agent-review-in-progress AI review is currently running for this PR labels Jul 23, 2026
@MauiBot MauiBot added s/agent-changes-requested AI agent recommends changes - found a better alternative or issues s/agent-gate-passed AI verified tests catch the bug (fail without fix, pass with fix) s/agent-fix-pr-picked 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 Jul 23, 2026
MauiBot

This comment was marked as outdated.

@MauiBot MauiBot added s/agent-fix-win AI found a better alternative fix than the PR and removed s/agent-review-in-progress AI review is currently running for this PR s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates labels Jul 23, 2026

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

AI Review Summary

@SyedAbdulAzeemSF4852 — new AI review results are available based on this last commit: c14b71c.

Gate Passed Confidence Low Platform Windows


🗂️ Review Sessions — click to expand
🚦 Gate — Test Before & After Fix

Gate Result: ✅ PASSED

Platform: WINDOWS · Base: main · Merge base: 997d875b

Test Without Fix (expect FAIL) With Fix (expect PASS)
📱 EntryHandlerTests (PasswordKeyboardRespectsIsPasswordFalseInitially, PasswordKeyboardIsPasswordToggleWorksCorrectly) Category=Entry ✅ FAIL — 363s ✅ PASS — 215s
🔴 Without fix — 📱 EntryHandlerTests (PasswordKeyboardRespectsIsPasswordFalseInitially, PasswordKeyboardIsPasswordToggleWorksCorrectly): FAIL ✅ · 363s

(no coded error found; showing last 1200 chars)

fying `x:SuppressXamlTrimWarnings=True` within the closest element. If not, the property path might be trimmed and will not be AOT compatible. [D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net10.0-windows10.0.19041.0]
Platform\Windows\TabbedPage\TabbedPageStyle.xaml(13,13): XamlCompiler warning WMC1510: Ensure the property path is trimming and AOT compatible by making use of 'Compiled Bindings (x:bind)' if possible or by specifying the 'x:DataType' directive with the respective binding data context and marking the type declaration with the 'WinRT.GeneratedBindableCustomProperty' attribute or the 'Microsoft.UI.Xaml.Data.Bindable' attribute. If you are unable to do either but can ensure the data type is attributed correctly, then you can also suppress the warning by specifying `x:SuppressXamlTrimWarnings=True` within the closest element. If not, the property path might be trimmed and will not be AOT compatible. [D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net10.0-windows10.0.19041.0]
    90 Warning(s)
    0 Error(s)

Time Elapsed 00:03:34.44
  Passed: 0
  Failed: 2
  Skipped: 0
  Total: 2
  Tests completed with exit code: 1

🟢 With fix — 📱 EntryHandlerTests (PasswordKeyboardRespectsIsPasswordFalseInitially, PasswordKeyboardIsPasswordToggleWorksCorrectly): PASS ✅ · 215s

(no coded error found; showing last 1200 chars)

ou can also suppress the warning by specifying `x:SuppressXamlTrimWarnings=True` within the closest element. If not, the property path might be trimmed and will not be AOT compatible. [D:\a\1\s\src\Core\src\Core.csproj::TargetFramework=net10.0-windows10.0.19041.0]
Platform\Windows\Styles\WindowRootViewStyle.xaml(31,17): XamlCompiler warning WMC1510: Ensure the property path is trimming and AOT compatible by making use of 'Compiled Bindings (x:bind)' if possible or by specifying the 'x:DataType' directive with the respective binding data context and marking the type declaration with the 'WinRT.GeneratedBindableCustomProperty' attribute or the 'Microsoft.UI.Xaml.Data.Bindable' attribute. If you are unable to do either but can ensure the data type is attributed correctly, then you can also suppress the warning by specifying `x:SuppressXamlTrimWarnings=True` within the closest element. If not, the property path might be trimmed and will not be AOT compatible. [D:\a\1\s\src\Core\src\Core.csproj::TargetFramework=net10.0-windows10.0.19041.0]
    11 Warning(s)
    0 Error(s)

Time Elapsed 00:02:41.90
  Passed: 2
  Failed: 0
  Skipped: 0
  Total: 2
  Tests completed successfully

📁 Fix files reverted (2 files)
  • src/Core/src/Platform/Windows/MauiPasswordTextBox.cs
  • src/Core/src/Platform/iOS/KeyboardExtensions.cs

📱 UI Tests — Entry,ViewBaseTests

Detected UI test categories: Entry,ViewBaseTests

Deep UI tests — 216 passed, 0 failed across 2 categories on platform-pool agent (replaces in-process counts above).

🧪 UI Test Execution Results (deep, platform pool)

Category Tests Snapshot diffs
Entry 101/102 ✓
ViewBaseTests 115/115 ✓
📎 Download drop-deep-uitests artifact (TRX + snapshot diffs)

📋 Pre-Flight — Context & Validation

Issue: #35650 - Entry IsPassword ignored when Keyboard is Password
PR: #36677 - [iOS And Windows] Fix Entry IsPassword ignored when Keyboard is set to Password
Platforms Affected: iOS, MacCatalyst, Windows
Files Changed: 2 implementation, 1 test

Key Findings

  • PR removes iOS secure-entry behavior from shared KeyboardExtensions.ApplyKeyboard(Keyboard.Password), which affects Editor/SearchBar as well as Entry.
  • Windows PR fix removes MauiPasswordTextBox InputScope callback entirely; this is scoped to Entry's platform view but changes how password input scopes can drive masking internally.
  • Gate already passed: the two Entry device tests fail without the fix and pass with the PR fix on Windows.

Code Review Summary

Verdict: NEEDS_CHANGES
Confidence: low
Errors: 1 | Warnings: 0 | Suggestions: 0

Key code review findings:

  • src/Core/src/Platform/iOS/KeyboardExtensions.cs:43-46 — Removing SetSecureTextEntry(true) from the shared keyboard helper regresses non-Entry iOS/MacCatalyst consumers of Keyboard.Password.

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #36677 Remove iOS shared SetSecureTextEntry(true) and remove Windows InputScope password callback ✅ PASSED (Gate) KeyboardExtensions.cs, MauiPasswordTextBox.cs, tests Original PR; passes Entry gate but code review found iOS blast-radius concern

🔬 Code Review — Deep Analysis

Code Review — PR #36677

Independent Assessment

What this changes: Makes Entry.IsPassword control masking when Keyboard=Password on iOS/MacCatalyst and Windows; adds non-Android device tests for the false initial state and false→true→false toggling.
Inferred motivation: Prevent Keyboard.Password from overriding an explicit IsPassword=false.

Reconciliation with PR Narrative

Author claims: iOS/Windows ignore IsPassword=false when Keyboard=Password; Android is tracked separately.
Agreement/disagreement: The Windows change is scoped to Entry. The iOS change is broader than the PR narrative because it changes the shared KeyboardExtensions.ApplyKeyboard path used by Entry, Editor, and SearchBar.

Prior Review Reconciliation

No prior ❌ Error findings found. I checked top-level review bodies, inline review comments, and PR issue comments via public GitHub API. Existing MauiBot review had warnings/suggestions and CI/test markers, but no unresolved ❌ code-review Error findings.

Blast Radius Assessment

  • Runs for all instances: No for Windows; yes for all iOS/MacCatalyst controls that use ApplyKeyboard(Keyboard.Password).
  • Startup impact: No.
  • Static/shared state: No new static/shared state.
  • Handler/platform impact: Yes — platform text-input behavior, max confidence medium before CI; CI/auth gaps cap to low.

CI Status

  • Required-check result: undetermined via required-check API; gh pr checks --required failed because GitHub CLI is unauthenticated.
  • Public check-runs: maui-pr success, maui-pr-devicetests success, maui-pr-uitests failure, Build Analysis failure, pre_activation failure.
  • Classification: red/undetermined. Public Build Analysis points to likely unrelated UI/infra failures, but required-check status could not be verified.
  • Action taken: invoked azdo-build-investigator; ci-analysis skill unavailable in this environment; confidence capped low.

Findings

❌ Error — iOS fix changes Keyboard.Password behavior for non-Entry controls

src/Core/src/Platform/iOS/KeyboardExtensions.cs:43-46 removes SetSecureTextEntry(true) from the shared keyboard mapper. That fixes Entry only because Entry has a later UpdateIsPassword source of truth, but Editor and SearchBar also call this same ApplyKeyboard path and do not have IsPassword. For those controls, Keyboard.Password previously enabled secure text entry on iOS/MacCatalyst; after this PR it no longer does. The fix should be scoped to Entry, e.g. by reapplying entry.IsPassword after Entry keyboard mapping, rather than removing password behavior from the shared keyboard helper.

Failure-Mode Probing

  • Entry Keyboard=Password, IsPassword=false: fixed on iOS/Windows.
  • Entry IsPassword toggle: existing mapper still updates native masking.
  • Editor/SearchBar Keyboard=Password on iOS: now unmasked because no later IsPassword mapper exists.
  • Handler reconnect/subscriptions: Windows removes a callback; no new subscription accumulation.

Verdict: NEEDS_CHANGES

Confidence: low
Summary: The Entry-specific goal is sound, but the iOS implementation is overbroad and regresses other Keyboard.Password consumers. CI required-check status could not be verified due missing GitHub auth, and public checks are not fully green.


🛠️ Fix — Analysis & Comparison

Fix Candidates

# Source Approach Test Result Files Changed Notes
1 try-fix Restore shared/native password behavior and reapply UpdateIsPassword from Entry MapKeyboard ❌ FAIL 4 files Mapper ordering alone did not beat the Windows InputScope callback; both Entry tests failed initial false assertion.
2 try-fix Preserve shared iOS secure-entry and Windows callback, but suppress callback only for mapper/internal InputScope assignments; reapply Entry IsPassword after keyboard mapping ✅ PASS 5 files Windows Entry device tests passed; avoids PR's iOS Editor/SearchBar regression by restoring shared Keyboard.Password behavior.
PR PR #36677 Remove iOS shared SetSecureTextEntry(true) and remove Windows InputScope password callback ✅ PASSED (Gate) 2 implementation files + tests Original PR passes gate but code review found iOS shared-helper blast radius.

Cross-Pollination

Model Round New Ideas? Details
code-review + maui-expert-reviewer 1 Yes Found iOS blast-radius issue: shared KeyboardExtensions.ApplyKeyboard(Keyboard.Password) affects Editor/SearchBar, so alternatives should preserve shared behavior and scope Entry-specific override elsewhere.
try-fix loop 1 Yes Candidate 1 proved mapper reordering alone is insufficient on Windows because the native InputScope callback still mutates IsPassword.
try-fix loop 2 Yes Candidate 2 added scoped suppression for mapper-owned/internal InputScope assignments and passed Windows Entry tests.

Exhausted: No — stopped because Candidate #2 passed the Windows gate criteria and is demonstrably better than the PR fix.
Selected Fix: Candidate #2 — preserves existing shared iOS Keyboard.Password behavior for non-Entry controls while keeping Entry IsPassword authoritative on Windows and iOS.

Candidate Narratives

try-fix-1

See CustomAgentLogsTmp/PRState/36677/PRAgent/try-fix-1/content.md for the full approach, diff, test output summary, and failure analysis.

try-fix-2

See CustomAgentLogsTmp/PRState/36677/PRAgent/try-fix-2/content.md for the full approach, diff, test output summary, and success analysis.


📝 Recommended PR Title & Description

Assessment: ✏️ Recommend updating — the current metadata accurately describes the submitted PR, but the winning fix is try-fix-2, which preserves shared iOS and Windows password-keyboard behavior instead of removing it.

Recommended title

[iOS and Windows] Entry: Respect IsPassword when Keyboard is Password

Recommended description

### Issue Details
- An Entry with Keyboard="Password" always renders text as masked, ignoring IsPassword=false. Setting IsPassword=false has no effect on iOS/MacCatalyst and Windows when Keyboard="Password" is set.

### Root Cause
- On initial setup, Entry keyboard mapping can run after IsPassword mapping. The shared iOS Keyboard.Password path sets SecureTextEntry=true, and Windows MauiPasswordTextBox reacts to an InputScope=Password assignment by setting IsPassword=true. Both paths can overwrite an explicit IsPassword=false.

### Description of Change
- **iOS/MacCatalyst**: Preserve the shared Keyboard.Password behavior in KeyboardExtensions.ApplyKeyboard so non-Entry consumers such as Editor, SearchBar, alert prompt text fields, Shell search, and compatibility renderers continue to mask password keyboards. EntryHandler.iOS now reapplies UpdateIsPassword after UpdateKeyboard so Entry.IsPassword remains authoritative for Entry.
- **Windows**: Preserve the MauiPasswordTextBox InputScope password callback for non-mapper/native InputScope changes, but suppress that callback for MAUI-owned/internal InputScope assignments. EntryHandler.Windows now reapplies UpdateIsPassword after UpdateKeyboard so Entry.IsPassword remains authoritative for Entry.
- **Tests**: Added non-Android Entry device tests covering Keyboard.Password with IsPassword=false initially and IsPassword false -> true -> false toggling.

### What NOT to Do (for future agents)
- Do not remove SetSecureTextEntry(true) from the shared iOS KeyboardExtensions.ApplyKeyboard(Keyboard.Password) helper; it affects non-Entry controls that do not have an IsPassword mapper.
- Do not rely on Entry mapper ordering alone on Windows; the MauiPasswordTextBox InputScopeProperty callback can still flip IsPassword=true.
- Do not remove the Windows InputScope callback entirely when a scoped suppression is sufficient; preserving native/non-mapper behavior reduces compatibility risk.

**Note**: The Android fix for the same issue is tracked separately in PR #36280.

### Issues Fixed
Fixes #35650

### Validated the behaviour in the following platforms

- [x] Windows
- [ ] Android
- [x] iOS
- [x] Mac

### Output

| Platform | Before | After |
|----------|----------|----------|
| iOS | <video src="https://github.com/user-attachments/assets/1b249d36-8e83-434c-a7dc-b7a4b9c5a3f4"> | <video src="https://github.com/user-attachments/assets/1c917876-aa8f-4c39-93ca-22b6b592f213"> |
| Windows | <video src="https://github.com/user-attachments/assets/80ae3ff3-5c9b-4211-9451-eeb9fc13c126"> | <video src="https://github.com/user-attachments/assets/fdd830fe-8017-4b12-882d-bf118be4a9f1"> |

🏁 Report — Final Recommendation

Comparative Report — PR #36677

Candidate ranking

Rank Candidate Regression tests Assessment
1 try-fix-2 ✅ PASS Best fix. Preserves shared/native password behavior for non-Entry consumers while making Entry IsPassword authoritative through scoped mapper/internal overrides.
2 pr-plus-reviewer Not rerun; based on PR Windows gate + reviewer-applied iOS correction Better than raw PR because it fixes the iOS shared-helper regression, but still removes the Windows MauiPasswordTextBox InputScope password callback entirely.
3 pr ✅ PASSED gate Passes the targeted Entry gate, but the expert reviewer found a major iOS/MacCatalyst blast-radius issue: shared Keyboard.Password no longer masks non-Entry consumers.
4 try-fix-1 ❌ FAIL Ranked below all passing candidates per rule. Mapper reapplication alone did not beat the Windows InputScope callback; both Entry tests failed their initial IsPassword=false assertion.

Candidate details

pr

The submitted PR removes two platform-level forcing mechanisms: iOS shared KeyboardExtensions.ApplyKeyboard(Keyboard.Password) no longer calls SetSecureTextEntry(true), and Windows MauiPasswordTextBox no longer observes InputScopeProperty to set IsPassword=true. This passes the targeted Entry gate on Windows, and prior review evidence records iOS Entry gate success as well. However, the iOS change is not Entry-scoped: Editor, SearchBar, alert prompts, Shell search, and compatibility renderers all call the same shared helper and do not have an Entry.IsPassword mapper to restore password masking.

pr-plus-reviewer

The sandbox candidate applies the expert reviewer's feedback to the PR by restoring shared iOS Keyboard.Password masking and reapplying Entry UpdateIsPassword after Entry UpdateKeyboard. This resolves the major iOS blast-radius finding while keeping the PR's Windows deletion approach. It is a viable improvement over the raw PR, but it does not preserve the Windows native/InputScope behavior for non-mapper changes.

try-fix-1

This candidate restored shared iOS secure-entry behavior and the Windows InputScope callback, then re-applied UpdateIsPassword from Entry MapKeyboard. It failed the Windows regression tests: the native InputScope callback still flipped IsPassword=true before validation. Because candidates that failed regression tests must rank below passing candidates, it cannot win.

try-fix-2

This candidate preserves the shared iOS Keyboard.Password behavior and the Windows InputScope callback, but scopes suppression to MAUI-owned/internal InputScope assignments. It also reapplies Entry UpdateIsPassword after Entry UpdateKeyboard on iOS and Windows. The final Windows Entry device test run passed (Passed: 1979, Failed: 0, Skipped: 111), and the approach directly incorporates the learning from try-fix-1 by also routing cached InputScope restoration through the scoped setter.

Winning candidate

try-fix-2 wins. It is the only candidate that both passes the regression tests and avoids the PR's broad behavior regression by preserving existing shared/native password semantics outside the Entry mapper-owned update path.


🧭 Next Steps — alternative fix proposed (try-fix-2)

Automated review — alternative fix proposed

The expert-reviewer evaluation compared the PR fix against automatically generated candidates and selected try-fix-2 as the strongest fix.

Why: try-fix-2 passed the Windows Entry regression suite and is safer than the raw PR because it preserves shared iOS Keyboard.Password behavior and the Windows InputScope callback except during MAUI-owned/internal Entry updates. It avoids the expert reviewer's iOS blast-radius finding while making Entry IsPassword authoritative for the failing scenarios.

Please consider applying the candidate diff below (or use it as guidance). Once you push an update, this workflow will re-trigger and re-evaluate.

Candidate diff (try-fix-2)
diff --git a/src/Core/src/Handlers/Entry/EntryHandler.Windows.cs b/src/Core/src/Handlers/Entry/EntryHandler.Windows.cs
index 6b7ec0c2d8..7494c43588 100644
--- a/src/Core/src/Handlers/Entry/EntryHandler.Windows.cs
+++ b/src/Core/src/Handlers/Entry/EntryHandler.Windows.cs
@@ -97,8 +97,11 @@ namespace Microsoft.Maui.Handlers
 		public static void MapCharacterSpacing(IEntryHandler handler, IEntry entry) =>
 			handler.PlatformView?.UpdateCharacterSpacing(entry);
 
-		public static void MapKeyboard(IEntryHandler handler, IEntry entry) =>
+		public static void MapKeyboard(IEntryHandler handler, IEntry entry)
+		{
 			handler.PlatformView?.UpdateKeyboard(entry);
+			handler.PlatformView?.UpdateIsPassword(entry);
+		}
 
 		public static void MapCursorPosition(IEntryHandler handler, IEntry entry) =>
 			handler.PlatformView?.UpdateCursorPosition(entry);
diff --git a/src/Core/src/Handlers/Entry/EntryHandler.iOS.cs b/src/Core/src/Handlers/Entry/EntryHandler.iOS.cs
index ec57791509..a6520caad5 100644
--- a/src/Core/src/Handlers/Entry/EntryHandler.iOS.cs
+++ b/src/Core/src/Handlers/Entry/EntryHandler.iOS.cs
@@ -108,8 +108,11 @@ namespace Microsoft.Maui.Handlers
 		public static void MapIsReadOnly(IEntryHandler handler, IEntry entry) =>
 			handler.PlatformView?.UpdateIsReadOnly(entry);
 
-		public static void MapKeyboard(IEntryHandler handler, IEntry entry) =>
+		public static void MapKeyboard(IEntryHandler handler, IEntry entry)
+		{
 			handler.PlatformView?.UpdateKeyboard(entry);
+			handler.PlatformView?.UpdateIsPassword(entry);
+		}
 
 		public static void MapReturnType(IEntryHandler handler, IEntry entry) =>
 			handler.PlatformView?.UpdateReturnType(entry);
diff --git a/src/Core/src/Platform/Windows/MauiPasswordTextBox.cs b/src/Core/src/Platform/Windows/MauiPasswordTextBox.cs
index 4f0536eeb6..c782832fdd 100644
--- a/src/Core/src/Platform/Windows/MauiPasswordTextBox.cs
+++ b/src/Core/src/Platform/Windows/MauiPasswordTextBox.cs
@@ -56,11 +56,41 @@ namespace Microsoft.Maui.Platform
 		bool _internalChangeFlag;
 		int _cachedCursorPosition;
 		int _cachedTextLength;
+		bool _ignoreInputScopePasswordSync;
+		readonly long _token;
 
 		public MauiPasswordTextBox()
 		{
 			TextChanging += OnNativeTextChanging;
 			TextChanged += OnNativeTextChanged;
+			_token = RegisterPropertyChangedCallback(TextBox.InputScopeProperty, OnInputScopePropertyChanged);
+			Unloaded += (s, e) =>
+			{
+				UnregisterPropertyChangedCallback(TextBox.InputScopeProperty, _token);
+			};
+		}
+
+		static void OnInputScopePropertyChanged(DependencyObject sender, DependencyProperty dp)
+		{
+			if (sender is not MauiPasswordTextBox mauiTxtBox || mauiTxtBox.IsPassword || mauiTxtBox._ignoreInputScopePasswordSync)
+			{
+				return;
+			}
+
+			mauiTxtBox.IsPassword = mauiTxtBox.InputScope?.Names?.Any(x => x.NameValue == InputScopeNameValue.Password) ?? false;
+		}
+
+		internal void SetInputScopeFromMapper(InputScope? inputScope)
+		{
+			_ignoreInputScopePasswordSync = true;
+			try
+			{
+				InputScope = inputScope;
+			}
+			finally
+			{
+				_ignoreInputScopePasswordSync = false;
+			}
 		}
 
 		public bool IsPassword
@@ -206,7 +236,7 @@ namespace Microsoft.Maui.Platform
 		{
 			if (!IsPassword)
 			{
-				InputScope = _cachedInputScope;
+				SetInputScopeFromMapper(_cachedInputScope);
 				IsSpellCheckEnabled = _cachedSpellCheckSetting;
 				IsTextPredictionEnabled = _cachedPredictionsSetting;
 			}
diff --git a/src/Core/src/Platform/Windows/TextBoxExtensions.cs b/src/Core/src/Platform/Windows/TextBoxExtensions.cs
index f57fb5b977..0d2af7a616 100644
--- a/src/Core/src/Platform/Windows/TextBoxExtensions.cs
+++ b/src/Core/src/Platform/Windows/TextBoxExtensions.cs
@@ -207,7 +207,10 @@ namespace Microsoft.Maui.Platform
 
 			inputScope.Names.Add(textInput.Keyboard?.ToInputScopeName() ?? new InputScopeName(InputScopeNameValue.Default));
 
-			textBox.InputScope = inputScope;
+			if (textBox is MauiPasswordTextBox passwordTextBox)
+				passwordTextBox.SetInputScopeFromMapper(inputScope);
+			else
+				textBox.InputScope = inputScope;
 		}
 
 		public static void UpdateHorizontalTextAlignment(this TextBox textBox, ITextAlignment textAlignment)
diff --git a/src/Core/src/Platform/iOS/KeyboardExtensions.cs b/src/Core/src/Platform/iOS/KeyboardExtensions.cs
index 863810a4b3..9b7b72a3cc 100644
--- a/src/Core/src/Platform/iOS/KeyboardExtensions.cs
+++ b/src/Core/src/Platform/iOS/KeyboardExtensions.cs
@@ -43,6 +43,7 @@ namespace Microsoft.Maui.Platform
 			else if (keyboard == Keyboard.Password)
 			{
 				textInput.SetKeyboardType(UIKeyboardType.Default);
+				textInput.SetSecureTextEntry(true);
 			}
 			else if (keyboard is CustomKeyboard)
 			{

@kubaflo
kubaflo marked this pull request as ready for review July 27, 2026 08:49
Copilot AI review requested due to automatic review settings July 27, 2026 08:49
@kubaflo
kubaflo changed the base branch from main to inflight/current July 27, 2026 08:49
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
There may be pipelines that require an authorized user to comment /azp run to run.

@kubaflo
kubaflo merged commit cd474ce into dotnet:inflight/current Jul 27, 2026
156 of 169 checks passed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 a cross-platform inconsistency where Entry configured with Keyboard.Password could override IsPassword=false (initial load on iOS; initial load and runtime toggles on Windows). The change makes IsPassword the single source of truth for whether text is masked, while still allowing Keyboard.Password to influence keyboard/input-scope behavior.

Changes:

  • iOS: Stop forcing SecureTextEntry=true inside Keyboard.Password handling so IsPassword=false isn’t overwritten after mapping.
  • Windows: Remove the InputScope property-changed callback that forced IsPassword=true whenever the scope changed to Password.
  • Device tests: Add coverage to ensure Keyboard.Password respects IsPassword=false initially and when toggling (non-Android, since Android is tracked in #36280).

Reviewed changes

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

File Description
src/Core/tests/DeviceTests/Handlers/Entry/EntryHandlerTests.cs Adds device tests validating initial and toggled IsPassword behavior when Keyboard.Password is set (excluding Android).
src/Core/src/Platform/Windows/MauiPasswordTextBox.cs Removes InputScope-driven forcing of IsPassword, preventing silent overrides of app intent.
src/Core/src/Platform/iOS/KeyboardExtensions.cs Removes hardcoded secure-entry enabling from Keyboard.Password so masking follows IsPassword.

@github-actions github-actions Bot added this to the .NET 10 SR10 milestone Jul 27, 2026
kubaflo pushed a commit that referenced this pull request Jul 28, 2026
…o Password (#36677)

<!-- Please let the below note in for people that find this PR -->
> [!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](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Issue Details
- An Entry with Keyboard="Password" always renders text as masked,
ignoring IsPassword=false. Setting IsPassword=false has no effect on iOS
(initial load) and Windows (initial load and runtime toggle) when
Keyboard="Password" is set.

### Root Cause
- The MapIsPassword mapper runs before MapKeyboard in EntryHandler.cs on
initial setup, so Keyboard.Password hardcodes masking behavior in
ApplyKeyboard (iOS: SetSecureTextEntry(true)) and via an InputScope
callback (Windows: OnInputScopePropertyChanged), both of which run after
MapIsPassword and silently overwrite IsPassword=false.

### Description of Change
- **iOS**: Removed the hardcoded SetSecureTextEntry(true) from the
Keyboard.Password branch in KeyboardExtensions.cs. SecureTextEntry is
now set exclusively by TextFieldExtensions.UpdateIsPassword, respecting
the actual IsPassword value.
- **Windows**: Removed the OnInputScopePropertyChanged callback from
MauiPasswordTextBox that automatically forced IsPassword=true whenever
InputScope changed to Password, allowing developers to set
IsPassword=false even when Keyboard=Password is used.

**Note**: The Android fix for the same issue is tracked separately in PR
#36280.


### Issues Fixed
Fixes #35650

### Validated the behaviour in the following platforms

- [x] Windows
- [ ] Android
- [x] iOS
- [x] Mac

### Output

| Platform | Before | After |
|----------|----------|----------|
| iOS | <video
src="https://github.com/user-attachments/assets/1b249d36-8e83-434c-a7dc-b7a4b9c5a3f4">
| <video
src="https://github.com/user-attachments/assets/1c917876-aa8f-4c39-93ca-22b6b592f213">
|
| Windows | <video
src="https://github.com/user-attachments/assets/80ae3ff3-5c9b-4211-9451-eeb9fc13c126">
| <video
src="https://github.com/user-attachments/assets/fdd830fe-8017-4b12-882d-bf118be4a9f1">
|
kubaflo pushed a commit that referenced this pull request Jul 29, 2026
…o Password (#36677)

<!-- Please let the below note in for people that find this PR -->
> [!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](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Issue Details
- An Entry with Keyboard="Password" always renders text as masked,
ignoring IsPassword=false. Setting IsPassword=false has no effect on iOS
(initial load) and Windows (initial load and runtime toggle) when
Keyboard="Password" is set.

### Root Cause
- The MapIsPassword mapper runs before MapKeyboard in EntryHandler.cs on
initial setup, so Keyboard.Password hardcodes masking behavior in
ApplyKeyboard (iOS: SetSecureTextEntry(true)) and via an InputScope
callback (Windows: OnInputScopePropertyChanged), both of which run after
MapIsPassword and silently overwrite IsPassword=false.

### Description of Change
- **iOS**: Removed the hardcoded SetSecureTextEntry(true) from the
Keyboard.Password branch in KeyboardExtensions.cs. SecureTextEntry is
now set exclusively by TextFieldExtensions.UpdateIsPassword, respecting
the actual IsPassword value.
- **Windows**: Removed the OnInputScopePropertyChanged callback from
MauiPasswordTextBox that automatically forced IsPassword=true whenever
InputScope changed to Password, allowing developers to set
IsPassword=false even when Keyboard=Password is used.

**Note**: The Android fix for the same issue is tracked separately in PR
#36280.


### Issues Fixed
Fixes #35650

### Validated the behaviour in the following platforms

- [x] Windows
- [ ] Android
- [x] iOS
- [x] Mac

### Output

| Platform | Before | After |
|----------|----------|----------|
| iOS | <video
src="https://github.com/user-attachments/assets/1b249d36-8e83-434c-a7dc-b7a4b9c5a3f4">
| <video
src="https://github.com/user-attachments/assets/1c917876-aa8f-4c39-93ca-22b6b592f213">
|
| Windows | <video
src="https://github.com/user-attachments/assets/80ae3ff3-5c9b-4211-9451-eeb9fc13c126">
| <video
src="https://github.com/user-attachments/assets/fdd830fe-8017-4b12-882d-bf118be4a9f1">
|
kubaflo pushed a commit that referenced this pull request Aug 7, 2026
…o Password (#36677)

<!-- Please let the below note in for people that find this PR -->
> [!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](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Issue Details
- An Entry with Keyboard="Password" always renders text as masked,
ignoring IsPassword=false. Setting IsPassword=false has no effect on iOS
(initial load) and Windows (initial load and runtime toggle) when
Keyboard="Password" is set.

### Root Cause
- The MapIsPassword mapper runs before MapKeyboard in EntryHandler.cs on
initial setup, so Keyboard.Password hardcodes masking behavior in
ApplyKeyboard (iOS: SetSecureTextEntry(true)) and via an InputScope
callback (Windows: OnInputScopePropertyChanged), both of which run after
MapIsPassword and silently overwrite IsPassword=false.

### Description of Change
- **iOS**: Removed the hardcoded SetSecureTextEntry(true) from the
Keyboard.Password branch in KeyboardExtensions.cs. SecureTextEntry is
now set exclusively by TextFieldExtensions.UpdateIsPassword, respecting
the actual IsPassword value.
- **Windows**: Removed the OnInputScopePropertyChanged callback from
MauiPasswordTextBox that automatically forced IsPassword=true whenever
InputScope changed to Password, allowing developers to set
IsPassword=false even when Keyboard=Password is used.

**Note**: The Android fix for the same issue is tracked separately in PR
#36280.


### Issues Fixed
Fixes #35650

### Validated the behaviour in the following platforms

- [x] Windows
- [ ] Android
- [x] iOS
- [x] Mac

### Output

| Platform | Before | After |
|----------|----------|----------|
| iOS | <video
src="https://github.com/user-attachments/assets/1b249d36-8e83-434c-a7dc-b7a4b9c5a3f4">
| <video
src="https://github.com/user-attachments/assets/1c917876-aa8f-4c39-93ca-22b6b592f213">
|
| Windows | <video
src="https://github.com/user-attachments/assets/80ae3ff3-5c9b-4211-9451-eeb9fc13c126">
| <video
src="https://github.com/user-attachments/assets/fdd830fe-8017-4b12-882d-bf118be4a9f1">
|
kubaflo pushed a commit that referenced this pull request Aug 12, 2026
…o Password (#36677)

<!-- Please let the below note in for people that find this PR -->
> [!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](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Issue Details
- An Entry with Keyboard="Password" always renders text as masked,
ignoring IsPassword=false. Setting IsPassword=false has no effect on iOS
(initial load) and Windows (initial load and runtime toggle) when
Keyboard="Password" is set.

### Root Cause
- The MapIsPassword mapper runs before MapKeyboard in EntryHandler.cs on
initial setup, so Keyboard.Password hardcodes masking behavior in
ApplyKeyboard (iOS: SetSecureTextEntry(true)) and via an InputScope
callback (Windows: OnInputScopePropertyChanged), both of which run after
MapIsPassword and silently overwrite IsPassword=false.

### Description of Change
- **iOS**: Removed the hardcoded SetSecureTextEntry(true) from the
Keyboard.Password branch in KeyboardExtensions.cs. SecureTextEntry is
now set exclusively by TextFieldExtensions.UpdateIsPassword, respecting
the actual IsPassword value.
- **Windows**: Removed the OnInputScopePropertyChanged callback from
MauiPasswordTextBox that automatically forced IsPassword=true whenever
InputScope changed to Password, allowing developers to set
IsPassword=false even when Keyboard=Password is used.

**Note**: The Android fix for the same issue is tracked separately in PR
#36280.


### Issues Fixed
Fixes #35650

### Validated the behaviour in the following platforms

- [x] Windows
- [ ] Android
- [x] iOS
- [x] Mac

### Output

| Platform | Before | After |
|----------|----------|----------|
| iOS | <video
src="https://github.com/user-attachments/assets/1b249d36-8e83-434c-a7dc-b7a4b9c5a3f4">
| <video
src="https://github.com/user-attachments/assets/1c917876-aa8f-4c39-93ca-22b6b592f213">
|
| Windows | <video
src="https://github.com/user-attachments/assets/80ae3ff3-5c9b-4211-9451-eeb9fc13c126">
| <video
src="https://github.com/user-attachments/assets/fdd830fe-8017-4b12-882d-bf118be4a9f1">
|
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration s/agent-changes-requested AI agent recommends changes - found a better alternative or issues s/agent-fix-win AI found a better alternative fix than the PR s/agent-gate-passed AI verified tests catch the bug (fail without fix, pass with fix) s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Android] Keyboard Password seems to force IsPassword to True on Entry

6 participants