Skip to content

Add BorderStyle property to Entry#33310

Open
mhrastegari wants to merge 13 commits into
dotnet:net11.0from
mhrastegari:33300-add-hasborder-property-to-entry
Open

Add BorderStyle property to Entry#33310
mhrastegari wants to merge 13 commits into
dotnet:net11.0from
mhrastegari:33300-add-hasborder-property-to-entry

Conversation

@mhrastegari

@mhrastegari mhrastegari commented Dec 28, 2025

Copy link
Copy Markdown

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 of Change

This change adds BorderStyle property to the Entry so that developers can easily create borderless inputs without custom handlers/renderers or platform-specific hacks.

Platform

  • Android
  • Windows
  • iOS
  • macOS

Issues Fixed

Fixes #33300
Fixes #7906

Screenshots

Platform Default focused Borderless focused
Windows image image
Android image image

@dotnet-policy-service dotnet-policy-service Bot added the community ✨ Community Contribution label Dec 28, 2025

@jfversluis jfversluis left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This would have to target the .NET 11 branch and also needs a good set of tests to make sure that none of the existing functionality is broken with this.

@mhrastegari

Copy link
Copy Markdown
Author

Sure @jfversluis I'll write the tests and reopen another PR that targets .NET 11 branch and put everything in it

@kubaflo

kubaflo commented Jan 4, 2026

Copy link
Copy Markdown
Contributor

What happens when you set hasBorder and, for example, a red background to entry?

@kubaflo

kubaflo commented Jan 4, 2026

Copy link
Copy Markdown
Contributor

Editor also has this underline :)

@kubaflo kubaflo 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.

I think that UITests would be valuable here

@kubaflo

kubaflo commented Jan 4, 2026

Copy link
Copy Markdown
Contributor

We should decide which approach is better. This or #33309. However, in my opinion, either of these would be a great addition to net11!

@mhrastegari

mhrastegari commented Jan 4, 2026

Copy link
Copy Markdown
Author

What happens when you set hasBorder and, for example, a red background to entry?

Good idea, I'll add the tests

@mhrastegari

Copy link
Copy Markdown
Author

Editor also has this underline :)

I agree this would be valuable. But I'd prefer to keep this PR focused on Entry first, then add Editor support in another PR once this one is approved.

@pictos pictos 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.

I did test and found some inconsistency between platforms. Android it adds an underline and iOS it adds a border around the entry. Since the property name is Border I would expect it to add a border around the entry, for Android, as well.

Image Image

@mhrastegari

Copy link
Copy Markdown
Author

Thanks for your feedback @pictos
If you’d prefer a stronger cross‑platform guarantee for example, introducing a property like BorderStyle to standardize boxed vs underline styles, I can give it a try, though it's a larger design change than this PR.

@pictos

pictos commented Jan 7, 2026

Copy link
Copy Markdown
Contributor

@mhrastegari I think the name is the main problem. As a mobile dev when I see Border property I would imagine a border wrapping my control, and probably that idea is because of Border control.

Also, if you go on google and type something like "edit text compat with border" or "UiTextView with border" will can see images of the control wrapped inside a border and not just the underline

@mhrastegari

Copy link
Copy Markdown
Author

How about BorderStyle enum instead of HasBorder boolean?

	public enum BorderStyle
	{
		/// <summary>
		/// Shows the platform's default border/decoration style.
		/// </summary>
		Default,

		/// <summary>
		/// Hides the border/decoration.
		/// </summary>
		None
	}

@pictos

pictos commented Jan 8, 2026

Copy link
Copy Markdown
Contributor

@mhrastegari I like it

@mhrastegari mhrastegari requested a review from pictos January 28, 2026 18:49
@mhrastegari

Copy link
Copy Markdown
Author

If this is Accepted, I'll close it and open a new PR targeting .NET 11 branch

@kubaflo

kubaflo commented Jan 29, 2026

Copy link
Copy Markdown
Contributor

@mhrastegari please don't close, just change a base :)

@mhrastegari mhrastegari changed the base branch from main to net11.0 January 30, 2026 07:43
@mhrastegari

Copy link
Copy Markdown
Author

Done @kubaflo

@mhrastegari mhrastegari changed the title Add HasBorder property to Entry Add BorderStyle property to Entry Jan 30, 2026
@rmarinho

Copy link
Copy Markdown
Member

/rebase

@MauiBot

MauiBot commented Mar 23, 2026

Copy link
Copy Markdown
Collaborator

⚠️ Merge Conflict Detected — This PR has merge conflicts with its target branch. Please rebase onto the target branch and resolve the conflicts.

@kubaflo

kubaflo commented May 24, 2026

Copy link
Copy Markdown
Contributor

@jfversluis what do you think?

@kubaflo

kubaflo commented May 24, 2026

Copy link
Copy Markdown
Contributor

/review -b feature/refactor-copilot-yml

@MauiBot

MauiBot commented May 24, 2026

Copy link
Copy Markdown
Collaborator

⚠️ Merge Conflict Detected — This PR has merge conflicts with its target branch. Please rebase onto the target branch and resolve the conflicts.

@kubaflo

kubaflo commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

AI code review for net11.0 target

Verdict: Needs changes (predicted build break from an incomplete rename)

This is a non-approval, automated review comment. It is advisory only — human approval is required.

What this PR does

Adds a new Entry.BorderStyle enum property (Default/None) to Microsoft.Maui + IEntry, with platform implementations for Android, iOS, MacCatalyst and Windows. Fixes #33300 / #7906.

Findings (blocking)

  • netstandard build break — leftover HasBorder naming. EntryHandler.cs (shared) registers [nameof(IEntry.BorderStyle)] = MapBorderStyle, and the iOS/Android/Windows partials define MapBorderStyle. But EntryHandler.Standard.cs defines MapHasBorder and has no MapBorderStyle (verified at head 365305a). The shared mapper dictionary compiles for the netstandard TFM, so Microsoft.Maui.Core (netstandard2.0) will fail to compile: "MapBorderStyle does not exist in the current context."
  • Tizen public API mismatch. Controls/.../net-tizen/PublicAPI.Unshipped.txt adds Entry.HasBorder / HasBorderProperty instead of BorderStyle / BorderStyleProperty (all other TFMs correctly add BorderStyle). This will trip the PublicAPI analyzer on Tizen (declared API not present; new BorderStyle undeclared).

Both look like remnants of a HasBorder (bool) → BorderStyle (enum) rename that wasn't fully propagated.

Findings (non-blocking)

  • iOS Default → UITextBorderStyle.RoundedRect matches the existing EntryHandler.iOS default (CreatePlatformView already sets RoundedRect), so there is no iOS visual regression. Good.
  • New file src/Core/src/Primitives/BorderStyle.cs uses 4-space indentation; the repo uses tabs — dotnet format will flag it.
  • Android UpdateBorderStyle: when Default and the API/theme guards aren't met (e.g. API < 23), it leaves the tint untouched, so switching None → Default on older APIs won't restore the accent tint. Minor edge case.

CI note

Only license/cla (pass) + Build Analysis (pending) are reported — the full maui-pr build has not run, so the netstandard/Tizen breaks above are not yet visible in checks. PR also has a merge conflict with net11.0.

Confidence: High on the netstandard MapBorderStyle break and the Tizen API mismatch.

@github-actions

github-actions Bot commented Jun 2, 2026

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 -- 33310

Or

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

@kubaflo

kubaflo commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

AI code review refresh for net11.0 target

Head reviewed: 7341703

Verdict: Needs changes — a compile-breaking leftover from the HasBorderBorderStyle rename is still present at head.

Blocking finding (high confidence)

  • src/Core/tests/DeviceTests/Stubs/EntryStub.cs initializes the enum property with a bool:
    public BorderStyle BorderStyle { get; set; } = true;
    Microsoft.Maui.BorderStyle is an enum (Default/None), so = true does not compile (CS0029: cannot implicitly convert bool to Microsoft.Maui.BorderStyle). This is exactly the incomplete-rename break flagged in the prior round and it is not yet fixed. It will break the Core DeviceTests build, which in turn prevents every new BorderStyle* device test in this PR from running. Suggested fix: = BorderStyle.Default; (or simply drop the initializer, since Default is 0).

Other observations (lower signal)

  • EntryHandler.Android.MapBorderStyle calls handler.UpdateValue(nameof(IEntry.Text)) before UpdateBorderStyle. Re-mapping Text from a border-style change is surprising; if it is there to re-apply tint after a text refresh, a brief comment would help. The companion test "Updating BorderStyle Does Not Affect Text" should catch regressions here.
  • Android UpdateBorderStyle: in the Default branch, when OperatingSystem.IsAndroidVersionAtLeast(23) is false or the accent attribute fails to resolve, the existing BackgroundTintList is left untouched, so switching NoneDefault may not restore the tint on older APIs / unusual themes. Minor edge case.
  • PublicAPI additions across Core and Controls TFMs (incl. tizen/netstandard) look consistent (Microsoft.Maui.BorderStyle, IEntry.BorderStyle.get, Entry.BorderStyle get/set + BorderStyleProperty, and the per-platform MapBorderStyle/UpdateBorderStyle). No HasBorder remnants remain in the public surface.

CI note

Only GitHub-app checks have reported so far (add-dogfood-comment pass, license/cla pass, Bump global.json skipping, Build Analysis pending). The AzDO maui-pr / device-test builds are not yet showing results. Given the EntryStub.cs issue above, the device-test build is expected to fail until the initializer is corrected — please don't treat the currently-green app checks as overall readiness.


Automated non-approving review refresh. This is not an approval or a request-changes; a human maintainer should make the final merge decision.

@kubaflo

kubaflo commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

AI code review refresh for net11.0 target

Head reviewed: 56a0df6
Target branch: net11.0 · State: open

Verdict: Needs changes (completeness/correctness gaps; not a CI blocker for this PR)

What changed since the prior round

  • The single new commit 56a0df6 ("fix EntryStub") resolves the prior build blocker: EntryStub.BorderStyle is now = BorderStyle.Default instead of the invalid = true (enum can't be assigned a bool). ✅ Confirmed fixed.

What looks good

  • BorderStyle enum (Default/None), IEntry.BorderStyle getter, Entry.BorderStyleProperty bindable property, and the shared EntryHandler.cs mapper entry are coherent.
  • iOS/Android/Windows handlers + UpdateBorderStyle extensions are implemented; device tests (BorderStyleInitializesCorrectly, BorderStyleUpdatesCorrectly + per-platform GetNativeBorderStyle) added.
  • iOS Default → UITextBorderStyle.RoundedRect matches the existing CreatePlatformView default (EntryHandler.iOS.cs:18), so no default-appearance regression.
  • PublicAPI updated for Core + Controls across net/net-android/net-ios/net-maccatalyst/net-windows/netstandard.

High-signal findings

  1. Tizen build break (medium-high). The shared EntryHandler.cs mapper now references MapBorderStyle, but EntryHandler.Tizen.cs does not define it (Tizen uses its own partial, not EntryHandler.Standard.cs). The -tizen TFM is built by Core.csproj (conditional ItemGroup at Core.csproj:75), so this would fail with CS0103 for Tizen consumers. Also, src/Core/src/PublicAPI/net-tizen/PublicAPI.Unshipped.txt was not updated (no Microsoft.Maui.BorderStyle / IEntry.BorderStyle.get), even though the Controls net-tizen file was. Default PR CI doesn't compile Tizen, so this won't show red here, but it's a real gap.
  2. EntryHandler2 (Android) ignores BorderStyle (medium). EntryHandler2.Android.cs defines its own Mapper (lines 18–41) which lacks [nameof(IEntry.BorderStyle)] = MapBorderStyle. When the EntryHandler2 path is active, setting BorderStyle is a silent no-op on Android.
  3. Android Default reset edge case (low-medium). In EditTextExtensions.UpdateBorderStyle, the Default branch only restores BackgroundTintList when OperatingSystem.IsAndroidVersionAtLeast(23) and the accent attribute resolves. If a user toggles None → Default on older API levels (or when the accent doesn't resolve), the tint stays transparent and the border is not restored. Consider clearing/resetting the tint to the original/default in the Default branch unconditionally.

CI note

gh pr checks shows only GitHub Actions checks: add-dogfood-comment pass, license/cla pass, Bump global.json skipping, Build Analysis pending. No failing required checks observed; the full AzDO maui-pr build/device-test legs are not reflected in gh pr checks, so build/test health for the platform legs (and especially the Tizen/EntryHandler2 gaps above, which CI may not cover) is unverified here. mergeStateStatus = BLOCKED (awaiting human review), mergeable = MERGEABLE.

Confidence

Medium-high on findings #1 and #2 (code-evident from the diff and current sources); medium on #3 (behavioral edge case, not verified on-device).


Non-approval disclaimer: This is an automated, advisory AI review refresh. It is not an approval and does not request changes via GitHub review state. A human maintainer must make the final merge decision.

@kubaflo kubaflo 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.

Synthesized review — PR #33310 (Entry BorderStyle API)

Verdict: NEEDS_CHANGES (confidence: high)
Head reviewed: 56a0df6 · Target: net11.0

The BorderStyle enum (Default/None), IEntry.BorderStyle, the Entry bindable property, and the iOS/Android/Windows handlers + device tests are coherent and well-formed. However, Tizen support is incomplete in a way that breaks the -tizen build, and the Android handler has two correctness issues. The Android cursor-reset finding below is net-new versus the prior automated review rounds (which already flagged the Tizen and Default-tint gaps).

Key findings (all code-confirmed at head)

  1. Tizen build break + incomplete coverage (error)EntryHandler.cs:32 adds MapBorderStyle to the shared mapper, but EntryHandler.Tizen.cs never defines it → CS0103 on the -tizen TFM (Core builds Tizen via Core.csproj). Same root cause: Core net-tizen/PublicAPI.Unshipped.txt wasn't updated (→ RS0016), and EntryHandler2.Android.cs (Material) has its own mapper missing BorderStyle (silent no-op).
  2. Android cursor reset (warning)EntryHandler.Android.cs:95 MapBorderStyle calls handler.UpdateValue(nameof(IEntry.Text)); Android UpdateText does SetSelection(Text.Length), moving the caret to the end on a border-only change. iOS/Windows don't do this; the call is unnecessary.
  3. Android Default tint fallback (suggestion)EditTextExtensions.cs:78 only restores the accent tint when API ≥ 23 and accent resolution succeeds; otherwise a prior None (transparent) tint persists and the underline stays invisible. Add an unconditional BackgroundTintList = null; fallback.

Dropped / not surfaced

  • IEntry.cs:16 "source-breaking interface addition" (gpt-5.5, error) — dropped as by-design: adding the member to IEntry + PublicAPI.Unshipped.txt is the sanctioned MAUI pattern for this feature (every other Entry property lives on IEntry).
  • Gemini's separate Controls net-tizen PublicAPI item was folded into finding #1 (that file was correctly updated; the real gap is Core net-tizen).

CI

GitHub Actions only: add-dogfood-comment pass, license/cla pass, Bump global.json skipping, Build Analysis pending. No failing required checks here, but gh pr checks does not reflect the AzDO maui-pr build/device-test legs — and default PR CI does not compile Tizen, so the CS0103/RS0016 Tizen gap will not turn this PR red despite being a real build break for Tizen consumers.

[nameof(IEntry.ClearButtonVisibility)] = MapClearButtonVisibility,
[nameof(IEntry.Font)] = MapFont,
[nameof(IEntry.IsPassword)] = MapIsPassword,
[nameof(IEntry.BorderStyle)] = MapBorderStyle,

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.

Tizen build break + incomplete platform coverage. Adding [nameof(IEntry.BorderStyle)] = MapBorderStyle to the shared mapper makes every TFM resolve MapBorderStyle, but EntryHandler.Tizen.cs never defines it (Tizen compiles its own partial, not EntryHandler.Standard.cs), so the -tizen TFM built by Core.csproj fails with CS0103. Two related gaps share the same root cause: (1) src/Core/src/PublicAPI/net-tizen/PublicAPI.Unshipped.txt was not updated with Microsoft.Maui.BorderStyle / Microsoft.Maui.IEntry.BorderStyle.get (RS0016 on the Tizen Core build, even though every other TFM's PublicAPI was updated); (2) EntryHandler2.Android.cs (Material) declares its own Mapper with no BorderStyle entry, so setting BorderStyle is a silent no-op on the Material Android path. Add a Tizen MapBorderStyle/UpdateBorderStyle, the net-tizen Core API entries, and the EntryHandler2 mapper entry. (Default PR CI does not compile Tizen, so this won't show red here, but it breaks Tizen consumers.)


public static void MapBorderStyle(IEntryHandler handler, IEntry entry)
{
handler.UpdateValue(nameof(IEntry.Text));

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.

MapBorderStyle calls handler.UpdateValue(nameof(IEntry.Text)) before applying the border-only change. On Android MapText -> UpdateText reassigns EditText.Text and calls SetSelection(Text.Length) (EditTextExtensions.cs:29), so toggling BorderStyle while the user is editing moves the caret to the end and re-runs text-side effects even though no text changed. iOS and Windows MapBorderStyle don't do this -- UpdateBorderStyle only touches BackgroundTintList, so this line is unnecessary (it appears copied from the MapIsPassword/InputType pattern, where it is justified). Remove it, and consider a regression test asserting CursorPosition/SelectionLength are preserved across a BorderStyle change.


public static void UpdateBorderStyle(this EditText editText, IEntry entry)
{
if (entry.BorderStyle is BorderStyle.Default)

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.

The Default branch only restores BackgroundTintList when OperatingSystem.IsAndroidVersionAtLeast(23) AND the accent attribute resolves AND the color state list is non-null. If any check fails (e.g. API < 23, or accent/attribute resolution fails) the method returns without touching the tint, so after toggling None -> Default the previously-set transparent tint persists and the underline stays invisible. Add an unconditional fallback at the end of the Default branch (e.g. editText.BackgroundTintList = null;) so the platform default tint is restored even when accent resolution fails.

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

Labels

community ✨ Community Contribution

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Entry and Editor: option to disable borders and underline (focus) [Entry] Add HasBorder property

6 participants