diff --git a/src/Controls/tests/Core.UnitTests/SafeAreaOrientationTests.cs b/src/Controls/tests/Core.UnitTests/SafeAreaOrientationTests.cs
new file mode 100644
index 000000000000..6a5028ccaa78
--- /dev/null
+++ b/src/Controls/tests/Core.UnitTests/SafeAreaOrientationTests.cs
@@ -0,0 +1,159 @@
+using Microsoft.Maui.Devices;
+using Microsoft.Maui.Graphics;
+using Xunit;
+
+namespace Microsoft.Maui.Controls.Core.UnitTests;
+
+public class SafeAreaOrientationTests : BaseTestFixture
+{
+ [Fact]
+ public void SafeAreaEdgesCanBeSetViaVisualStateManager()
+ {
+ DeviceDisplay.SetCurrent(new MockDeviceDisplay(
+ new(100, 200, 2, DisplayOrientation.Portrait, DisplayRotation.Rotation0)));
+
+ var page = new ContentPage();
+
+ VisualStateManager.SetVisualStateGroups(page, new VisualStateGroupList
+ {
+ new VisualStateGroup
+ {
+ Name = "OrientationStates",
+ States =
+ {
+ new VisualState
+ {
+ Name = "Portrait",
+ StateTriggers = { new OrientationStateTrigger { Orientation = DisplayOrientation.Portrait } },
+ Setters = { new Setter { Property = ContentPage.SafeAreaEdgesProperty, Value = SafeAreaEdges.All } }
+ },
+ new VisualState
+ {
+ Name = "Landscape",
+ StateTriggers = { new OrientationStateTrigger { Orientation = DisplayOrientation.Landscape } },
+ Setters = { new Setter { Property = ContentPage.SafeAreaEdgesProperty, Value = new SafeAreaEdges(SafeAreaRegions.All, SafeAreaRegions.None) } }
+ }
+ }
+ }
+ });
+
+ var window = new Window(page);
+
+ // Initially in portrait, should have All edges
+ Assert.Equal(SafeAreaEdges.All, page.SafeAreaEdges);
+ }
+
+ [Fact]
+ public void SafeAreaEdgesChangesWhenOrientationChanges()
+ {
+ var mockDeviceDisplay = new MockDeviceDisplay(
+ new(100, 200, 2, DisplayOrientation.Portrait, DisplayRotation.Rotation0));
+ DeviceDisplay.SetCurrent(mockDeviceDisplay);
+
+ var page = new ContentPage();
+
+ VisualStateManager.SetVisualStateGroups(page, new VisualStateGroupList
+ {
+ new VisualStateGroup
+ {
+ Name = "OrientationStates",
+ States =
+ {
+ new VisualState
+ {
+ Name = "Portrait",
+ StateTriggers = { new OrientationStateTrigger { Orientation = DisplayOrientation.Portrait } },
+ Setters = { new Setter { Property = ContentPage.SafeAreaEdgesProperty, Value = SafeAreaEdges.All } }
+ },
+ new VisualState
+ {
+ Name = "Landscape",
+ StateTriggers = { new OrientationStateTrigger { Orientation = DisplayOrientation.Landscape } },
+ Setters = { new Setter { Property = ContentPage.SafeAreaEdgesProperty, Value = new SafeAreaEdges(SafeAreaRegions.All, SafeAreaRegions.None) } }
+ }
+ }
+ }
+ });
+
+ var window = new Window(page);
+
+ // Initially in portrait
+ Assert.Equal(SafeAreaEdges.All, page.SafeAreaEdges);
+
+ // Change to landscape
+ mockDeviceDisplay.SetMainDisplayOrientation(DisplayOrientation.Landscape);
+
+ // Should now use different safe area edges (horizontal All, vertical None)
+ var expected = new SafeAreaEdges(SafeAreaRegions.All, SafeAreaRegions.None);
+ Assert.Equal(expected, page.SafeAreaEdges);
+
+ window.Page = null; // Cleanup
+ }
+
+ [Fact]
+ public void SafeAreaEdgesCanUseContainerRegion()
+ {
+ DeviceDisplay.SetCurrent(new MockDeviceDisplay(
+ new(100, 200, 2, DisplayOrientation.Portrait, DisplayRotation.Rotation0)));
+
+ var page = new ContentPage();
+
+ VisualStateManager.SetVisualStateGroups(page, new VisualStateGroupList
+ {
+ new VisualStateGroup
+ {
+ Name = "OrientationStates",
+ States =
+ {
+ new VisualState
+ {
+ Name = "Portrait",
+ StateTriggers = { new OrientationStateTrigger { Orientation = DisplayOrientation.Portrait } },
+ Setters = { new Setter { Property = ContentPage.SafeAreaEdgesProperty, Value = SafeAreaEdges.Container } }
+ }
+ }
+ }
+ });
+
+ var window = new Window(page);
+
+ // Should use Container region
+ Assert.Equal(SafeAreaEdges.Container, page.SafeAreaEdges);
+
+ window.Page = null; // Cleanup
+ }
+
+ [Fact]
+ public void SafeAreaEdgesWorksWithDifferentPageTypes()
+ {
+ DeviceDisplay.SetCurrent(new MockDeviceDisplay(
+ new(100, 200, 2, DisplayOrientation.Portrait, DisplayRotation.Rotation0)));
+
+ var contentPage = new ContentPage();
+ var tabbedPage = new TabbedPage();
+
+ VisualStateManager.SetVisualStateGroups(contentPage, new VisualStateGroupList
+ {
+ new VisualStateGroup
+ {
+ Name = "OrientationStates",
+ States =
+ {
+ new VisualState
+ {
+ Name = "Portrait",
+ StateTriggers = { new OrientationStateTrigger { Orientation = DisplayOrientation.Portrait } },
+ Setters = { new Setter { Property = ContentPage.SafeAreaEdgesProperty, Value = SafeAreaEdges.All } }
+ }
+ }
+ }
+ });
+
+ var window = new Window(contentPage);
+
+ // ContentPage should respect VSM
+ Assert.Equal(SafeAreaEdges.All, contentPage.SafeAreaEdges);
+
+ window.Page = null; // Cleanup
+ }
+}
diff --git a/src/Controls/tests/TestCases.HostApp/Issues/PageSafeAreaOrientationVSM.xaml b/src/Controls/tests/TestCases.HostApp/Issues/PageSafeAreaOrientationVSM.xaml
new file mode 100644
index 000000000000..aa427dea76d1
--- /dev/null
+++ b/src/Controls/tests/TestCases.HostApp/Issues/PageSafeAreaOrientationVSM.xaml
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Controls/tests/TestCases.HostApp/Issues/PageSafeAreaOrientationVSM.xaml.cs b/src/Controls/tests/TestCases.HostApp/Issues/PageSafeAreaOrientationVSM.xaml.cs
new file mode 100644
index 000000000000..a6d1f26b990a
--- /dev/null
+++ b/src/Controls/tests/TestCases.HostApp/Issues/PageSafeAreaOrientationVSM.xaml.cs
@@ -0,0 +1,48 @@
+namespace Maui.Controls.Sample.Issues;
+
+[Issue(IssueTracker.None, 0, "Page SafeAreaEdges with OrientationStateTrigger VSM Test", PlatformAffected.All)]
+public partial class PageSafeAreaOrientationVSM : ContentPage
+{
+ public PageSafeAreaOrientationVSM()
+ {
+ InitializeComponent();
+
+ // Monitor size changes for orientation detection
+ this.SizeChanged += OnSizeChanged;
+
+ // Update info when page appears
+ this.Appearing += OnPageAppearing;
+ }
+
+ private void OnPageAppearing(object sender, EventArgs e)
+ {
+ // Delay to allow layout to complete
+ Dispatcher.DispatchDelayed(TimeSpan.FromMilliseconds(500), UpdateInfo);
+ }
+
+ private void OnSizeChanged(object sender, EventArgs e)
+ {
+ // Update info when size changes (indicating orientation change)
+ Dispatcher.DispatchDelayed(TimeSpan.FromMilliseconds(100), UpdateInfo);
+ }
+
+ private void UpdateInfo()
+ {
+ try
+ {
+ // Determine orientation based on actual page dimensions
+ var isLandscape = this.Width > this.Height;
+ var orientationText = isLandscape ? "Landscape" : "Portrait";
+
+ OrientationLabel.Text = $"Orientation: {orientationText}";
+ SafeAreaEdgesLabel.Text = $"SafeAreaEdges: {this.SafeAreaEdges}";
+ PageDimensionsLabel.Text = $"Page Dimensions: {this.Width:F1} x {this.Height:F1}";
+ }
+ catch (Exception ex)
+ {
+ OrientationLabel.Text = $"Orientation: Error - {ex.Message}";
+ SafeAreaEdgesLabel.Text = "SafeAreaEdges: Error";
+ PageDimensionsLabel.Text = "Page Dimensions: Error";
+ }
+ }
+}
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/PageSafeAreaOrientationVSM.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/PageSafeAreaOrientationVSM.cs
new file mode 100644
index 000000000000..dbad457f95a2
--- /dev/null
+++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/PageSafeAreaOrientationVSM.cs
@@ -0,0 +1,96 @@
+#if IOS || ANDROID
+using NUnit.Framework;
+using UITest.Appium;
+using UITest.Core;
+
+namespace Microsoft.Maui.TestCases.Tests.Issues;
+
+public class PageSafeAreaOrientationVSM : _IssuesUITest
+{
+ public override string Issue => "Page SafeAreaEdges with OrientationStateTrigger VSM Test";
+
+ public PageSafeAreaOrientationVSM(TestDevice device) : base(device)
+ {
+ }
+
+ [Test]
+ [Category(UITestCategories.SafeAreaEdges)]
+ public void PageSafeAreaEdgesUpdatesWithOrientation()
+ {
+ // 1. Wait for initial state to load
+ var orientationLabel = App.WaitForElement("OrientationLabel");
+ var safeAreaEdgesLabel = App.WaitForElement("SafeAreaEdgesLabel");
+
+ // 2. Verify initial portrait state
+ var initialOrientation = orientationLabel.GetText();
+ var initialSafeAreaEdges = safeAreaEdgesLabel.GetText();
+
+ Assert.That(initialOrientation, Does.Contain("Portrait"),
+ "Should start in portrait orientation");
+ Assert.That(initialSafeAreaEdges, Does.Contain("Container"),
+ "SafeAreaEdges should be Container in portrait");
+
+ // 3. Change to landscape
+ App.SetOrientationLandscape();
+ Thread.Sleep(2000); // Wait for orientation change and VSM to trigger
+
+ // 4. Verify landscape state
+ var landscapeOrientation = App.WaitForElement("OrientationLabel").GetText();
+ var landscapeSafeAreaEdges = App.WaitForElement("SafeAreaEdgesLabel").GetText();
+
+ Assert.That(landscapeOrientation, Does.Contain("Landscape"),
+ "Should now be in landscape orientation");
+ Assert.That(landscapeSafeAreaEdges, Does.Contain("Container"),
+ "SafeAreaEdges should be Container in landscape");
+
+ // 5. Verify visual markers are still visible
+ var topLeftMarker = App.WaitForElement("TopLeftMarker");
+ var topRightMarker = App.WaitForElement("TopRightMarker");
+ var centerMarker = App.WaitForElement("CenterMarker");
+
+ Assert.That(topLeftMarker, Is.Not.Null, "Top left marker should be visible");
+ Assert.That(topRightMarker, Is.Not.Null, "Top right marker should be visible");
+ Assert.That(centerMarker, Is.Not.Null, "Center marker should be visible");
+
+ // 6. Change back to portrait
+ App.SetOrientationPortrait();
+ Thread.Sleep(2000); // Wait for orientation change and VSM to trigger
+
+ // 7. Verify back to portrait state
+ var finalOrientation = App.WaitForElement("OrientationLabel").GetText();
+ var finalSafeAreaEdges = App.WaitForElement("SafeAreaEdgesLabel").GetText();
+
+ Assert.That(finalOrientation, Does.Contain("Portrait"),
+ "Should be back in portrait orientation");
+ Assert.That(finalSafeAreaEdges, Does.Contain("Container"),
+ "SafeAreaEdges should still be Container in portrait");
+ }
+
+ [Test]
+ [Category(UITestCategories.SafeAreaEdges)]
+ public void PageVSMMultipleOrientationChanges()
+ {
+ // Test that the VSM handles multiple orientation changes correctly
+ var safeAreaEdgesLabel = App.WaitForElement("SafeAreaEdgesLabel");
+
+ for (int i = 0; i < 3; i++)
+ {
+ // Change to landscape
+ App.SetOrientationLandscape();
+ Thread.Sleep(1500);
+
+ var landscapeSafeArea = safeAreaEdgesLabel.GetText();
+ Assert.That(landscapeSafeArea, Does.Contain("Container"),
+ $"SafeAreaEdges should be Container in landscape (iteration {i + 1})");
+
+ // Change back to portrait
+ App.SetOrientationPortrait();
+ Thread.Sleep(1500);
+
+ var portraitSafeArea = safeAreaEdgesLabel.GetText();
+ Assert.That(portraitSafeArea, Does.Contain("Container"),
+ $"SafeAreaEdges should be Container in portrait (iteration {i + 1})");
+ }
+ }
+}
+#endif
diff --git a/src/Templates/src/templates/maui-mobile/Resources/Styles/Styles.xaml b/src/Templates/src/templates/maui-mobile/Resources/Styles/Styles.xaml
index 2a9a28bfca2a..c94b8cb72e39 100644
--- a/src/Templates/src/templates/maui-mobile/Resources/Styles/Styles.xaml
+++ b/src/Templates/src/templates/maui-mobile/Resources/Styles/Styles.xaml
@@ -443,6 +443,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+