diff --git a/src/Controls/samples/Controls.Sample.UITests/Issues/Issue21630.xaml b/src/Controls/samples/Controls.Sample.UITests/Issues/Issue21630.xaml
new file mode 100644
index 000000000000..72e84609c70d
--- /dev/null
+++ b/src/Controls/samples/Controls.Sample.UITests/Issues/Issue21630.xaml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/Controls/samples/Controls.Sample.UITests/Issues/Issue21630.xaml.cs b/src/Controls/samples/Controls.Sample.UITests/Issues/Issue21630.xaml.cs
new file mode 100644
index 000000000000..b27ef44a8bff
--- /dev/null
+++ b/src/Controls/samples/Controls.Sample.UITests/Issues/Issue21630.xaml.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.Maui.Controls;
+using Microsoft.Maui.Controls.Xaml;
+
+namespace Maui.Controls.Sample.Issues;
+
+[XamlCompilation(XamlCompilationOptions.Compile)]
+[Issue(IssueTracker.Github, 21630, "Entries in NavBar don't trigger keyboard scroll", PlatformAffected.iOS)]
+public partial class Issue21630 : ContentPage
+{
+ Page _page;
+ List _modalStack;
+
+ public Issue21630()
+ {
+ InitializeComponent();
+ Loaded += OnLoaded;
+ }
+
+ private void OnLoaded(object sender, EventArgs e)
+ {
+ _page = Application.Current.MainPage;
+ _modalStack = Navigation.ModalStack.ToList();
+ }
+
+ void SwapMainPageNav (object sender, EventArgs e)
+ {
+ Application.Current.MainPage = new NavigationPage(new Issue21630_navPage(_page, _modalStack));
+ }
+
+ void SwapMainPageShell (object sender, EventArgs e)
+ {
+ Application.Current.MainPage = new Issue21630_shellPage(_page, _modalStack);
+ }
+}
diff --git a/src/Controls/samples/Controls.Sample.UITests/Issues/Issue21630_navPage.xaml b/src/Controls/samples/Controls.Sample.UITests/Issues/Issue21630_navPage.xaml
new file mode 100644
index 000000000000..d43d940470d4
--- /dev/null
+++ b/src/Controls/samples/Controls.Sample.UITests/Issues/Issue21630_navPage.xaml
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ asdf
+ asdf
+ asdf
+ asdf
+ asdf
+ asdf
+ asdf
+ asdf
+ asdf
+ asdf
+ asdf
+ asdf
+ asdf
+ asdf
+ asdf
+ asdf
+ asdf
+ asdf
+ asdf
+ asdf
+ asdf
+ asdf
+ asdf
+ asdf
+ asdf
+ asdf
+ asdf
+ asdf
+ asdf
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Controls/samples/Controls.Sample.UITests/Issues/Issue21630_navPage.xaml.cs b/src/Controls/samples/Controls.Sample.UITests/Issues/Issue21630_navPage.xaml.cs
new file mode 100644
index 000000000000..5b6302e7824f
--- /dev/null
+++ b/src/Controls/samples/Controls.Sample.UITests/Issues/Issue21630_navPage.xaml.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Microsoft.Maui.Controls;
+
+namespace Maui.Controls.Sample.Issues;
+
+public partial class Issue21630_navPage : ContentPage
+{
+ Page _page;
+ List _modalStack;
+
+ public Issue21630_navPage()
+ {
+ InitializeComponent();
+ var bc = (ValueTuple>)Shell.Current.BindingContext;
+ _page = bc.Item1;
+ _modalStack = bc.Item2;
+ }
+
+ public Issue21630_navPage(Page page, List modalStack)
+ {
+ InitializeComponent();
+ _page = page;
+ _modalStack = modalStack;
+ }
+
+ void FocusNavBarEntryNav (object sender, EventArgs e)
+ {
+ NavBarEntryNav.Focus();
+ }
+
+ void FocusNavBarEntryShell (object sender, EventArgs e)
+ {
+ NavBarEntryShell.Focus();
+ }
+
+ async void RestoreMainPage (object sender, EventArgs e)
+ {
+ Application.Current.MainPage = _page;
+ await Task.Yield();
+
+ foreach(var page in _modalStack)
+ {
+ await _page.Navigation.PushModalAsync(page);
+ }
+ }
+}
diff --git a/src/Controls/samples/Controls.Sample.UITests/Issues/Issue21630_shellPage.xaml b/src/Controls/samples/Controls.Sample.UITests/Issues/Issue21630_shellPage.xaml
new file mode 100644
index 000000000000..24b88105c362
--- /dev/null
+++ b/src/Controls/samples/Controls.Sample.UITests/Issues/Issue21630_shellPage.xaml
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/src/Controls/samples/Controls.Sample.UITests/Issues/Issue21630_shellPage.xaml.cs b/src/Controls/samples/Controls.Sample.UITests/Issues/Issue21630_shellPage.xaml.cs
new file mode 100644
index 000000000000..6fc33ae43263
--- /dev/null
+++ b/src/Controls/samples/Controls.Sample.UITests/Issues/Issue21630_shellPage.xaml.cs
@@ -0,0 +1,14 @@
+using Microsoft.Maui.Controls;
+using System.Collections.Generic;
+
+namespace Maui.Controls.Sample.Issues
+{
+ public partial class Issue21630_shellPage : Shell
+ {
+ public Issue21630_shellPage(Page page, List modalStack)
+ {
+ InitializeComponent();
+ BindingContext = (page, modalStack);
+ }
+ }
+}
diff --git a/src/Controls/tests/UITests/Tests/Issues/Issue21630.cs b/src/Controls/tests/UITests/Tests/Issues/Issue21630.cs
new file mode 100644
index 000000000000..eb7d23fdb132
--- /dev/null
+++ b/src/Controls/tests/UITests/Tests/Issues/Issue21630.cs
@@ -0,0 +1,58 @@
+using NUnit.Framework;
+using UITest.Appium;
+using UITest.Core;
+
+namespace Microsoft.Maui.AppiumTests.Issues;
+
+public class Issue21630 : _IssuesUITest
+{
+ public override string Issue => "Entries in NavBar don't trigger keyboard scroll";
+
+ public Issue21630(TestDevice device)
+ : base(device)
+ { }
+
+ string NavBarEntry => "NavBarEntry";
+ string HeaderEntry => "HeaderEntry";
+ string FocusButton => "FocusButton";
+ string RestoreButton => "RestoreMainPageButton";
+
+ [TestCase("SwapNavigationPage")]
+ [TestCase("SwapShellPage")]
+ public void NavBarEntryDoesNotTriggerKeyboardScroll(string scenario)
+ {
+ try
+ {
+ var scenarioSuffix = scenario == "SwapNavigationPage" ? "NavigationPage" : "ShellPage";
+
+ App.WaitForElement(scenario);
+ App.Click(scenario);
+
+ var navBarEntry = App.WaitForElement(NavBarEntry + scenarioSuffix);
+ var navBarLocation = navBarEntry.GetRect();
+ var headerEntry = App.WaitForElement(HeaderEntry);
+ var headerLocation = headerEntry.GetRect();
+
+ App.Click(FocusButton + scenarioSuffix);
+
+ var newNavBarEntry = App.WaitForElement(NavBarEntry + scenarioSuffix);
+ var newNavBarEntryLocation = newNavBarEntry.GetRect();
+ Assert.AreEqual(navBarLocation, newNavBarEntryLocation);
+
+ var newHeaderEntry = App.WaitForElement(HeaderEntry);
+ var newHeaderLocation = newHeaderEntry.GetRect();
+
+ Assert.AreEqual(headerLocation, newHeaderLocation);
+
+ App.WaitForElement(RestoreButton);
+ App.Click(RestoreButton);
+ }
+ catch
+ {
+ // Just in case these tests leave the app in an unreliable state
+ App.ResetApp();
+ FixtureSetup();
+ throw;
+ }
+ }
+}