diff --git a/src/Components/Endpoints/src/PublicAPI.Unshipped.txt b/src/Components/Endpoints/src/PublicAPI.Unshipped.txt
index 7dc5c58110bf..ac1780ba883e 100644
--- a/src/Components/Endpoints/src/PublicAPI.Unshipped.txt
+++ b/src/Components/Endpoints/src/PublicAPI.Unshipped.txt
@@ -1 +1,3 @@
#nullable enable
+Microsoft.AspNetCore.Components.Endpoints.BasePath
+Microsoft.AspNetCore.Components.Endpoints.BasePath.BasePath() -> void
diff --git a/src/Components/Endpoints/src/Routing/BasePath.cs b/src/Components/Endpoints/src/Routing/BasePath.cs
new file mode 100644
index 000000000000..1e7435d2613e
--- /dev/null
+++ b/src/Components/Endpoints/src/Routing/BasePath.cs
@@ -0,0 +1,46 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Microsoft.AspNetCore.Components.Rendering;
+
+namespace Microsoft.AspNetCore.Components.Endpoints;
+
+///
+/// Renders a <base> element whose href value matches the current request path base.
+///
+public sealed class BasePath : IComponent
+{
+ private RenderHandle _renderHandle;
+
+ [Inject]
+ private NavigationManager NavigationManager { get; set; } = default!;
+
+ void IComponent.Attach(RenderHandle renderHandle)
+ {
+ _renderHandle = renderHandle;
+ }
+
+ Task IComponent.SetParametersAsync(ParameterView parameters)
+ {
+ _renderHandle.Render(Render);
+ return Task.CompletedTask;
+ }
+
+ private void Render(RenderTreeBuilder builder)
+ {
+ builder.OpenElement(0, "base");
+ builder.AddAttribute(1, "href", ComputeHref());
+ builder.CloseElement();
+ }
+
+ private string ComputeHref()
+ {
+ var baseUri = NavigationManager.BaseUri;
+ if (Uri.TryCreate(baseUri, UriKind.Absolute, out var absoluteUri))
+ {
+ return absoluteUri.AbsolutePath;
+ }
+
+ return "/";
+ }
+}
diff --git a/src/Components/Endpoints/test/Microsoft.AspNetCore.Components.Endpoints.Tests.csproj b/src/Components/Endpoints/test/Microsoft.AspNetCore.Components.Endpoints.Tests.csproj
index 3fe362d5d236..3d7bced6b251 100644
--- a/src/Components/Endpoints/test/Microsoft.AspNetCore.Components.Endpoints.Tests.csproj
+++ b/src/Components/Endpoints/test/Microsoft.AspNetCore.Components.Endpoints.Tests.csproj
@@ -6,8 +6,8 @@
-
+
diff --git a/src/Components/Endpoints/test/Routing/BasePathTest.cs b/src/Components/Endpoints/test/Routing/BasePathTest.cs
new file mode 100644
index 000000000000..ec2c4fa02fc6
--- /dev/null
+++ b/src/Components/Endpoints/test/Routing/BasePathTest.cs
@@ -0,0 +1,93 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Microsoft.AspNetCore.Components.RenderTree;
+using Microsoft.AspNetCore.Components.Test.Helpers;
+
+#nullable enable
+
+namespace Microsoft.AspNetCore.Components.Endpoints;
+
+public class BasePathTest
+{
+ [Fact]
+ public void PreservesCasingFromNavigationManagerBaseUri()
+ {
+ _ = CreateServices(out var renderer, "https://example.com/Dashboard/");
+ var componentId = RenderBasePath(renderer);
+
+ Assert.Equal("/Dashboard/", GetHref(renderer, componentId));
+ }
+
+ [Theory]
+ [InlineData("https://example.com/a/b/", "/a/b/")]
+ [InlineData("https://example.com/a/b", "/a/")]
+ public void RendersBaseUriPathExactly(string baseUri, string expected)
+ {
+ _ = CreateServices(out var renderer, baseUri);
+
+ var componentId = RenderBasePath(renderer);
+
+ Assert.Equal(expected, GetHref(renderer, componentId));
+ }
+
+ private static TestServiceProvider CreateServices(out TestRenderer renderer, string baseUri = "https://example.com/app/")
+ {
+ var services = new TestServiceProvider();
+ var uri = baseUri.EndsWith('/') ? baseUri + "dashboard" : baseUri + "/dashboard";
+ var navigationManager = new TestNavigationManager(baseUri, uri);
+ services.AddService(navigationManager);
+ services.AddService(services);
+
+ renderer = new TestRenderer(services);
+ return services;
+ }
+
+ private static int RenderBasePath(TestRenderer renderer)
+ {
+ var component = (BasePath)renderer.InstantiateComponent();
+ var componentId = renderer.AssignRootComponentId(component);
+ renderer.RenderRootComponent(componentId);
+ return componentId;
+ }
+
+ private static string? GetHref(TestRenderer renderer, int componentId)
+ {
+ var frames = renderer.GetCurrentRenderTreeFrames(componentId);
+ for (var i = 0; i < frames.Count; i++)
+ {
+ ref readonly var frame = ref frames.Array[i];
+ if (frame.FrameType == RenderTreeFrameType.Element && frame.ElementName == "base")
+ {
+ for (var j = i + 1; j < frames.Count; j++)
+ {
+ ref readonly var attribute = ref frames.Array[j];
+ if (attribute.FrameType == RenderTreeFrameType.Attribute && attribute.AttributeName == "href")
+ {
+ return attribute.AttributeValue?.ToString();
+ }
+
+ if (attribute.FrameType != RenderTreeFrameType.Attribute)
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private sealed class TestNavigationManager : NavigationManager
+ {
+ public TestNavigationManager(string baseUri, string uri)
+ {
+ Initialize(baseUri, uri);
+ }
+
+ protected override void NavigateToCore(string uri, bool forceLoad)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/src/Components/Samples/BlazorUnitedApp/App.razor b/src/Components/Samples/BlazorUnitedApp/App.razor
index e04f7fc9e8e4..17c3f20485ec 100644
--- a/src/Components/Samples/BlazorUnitedApp/App.razor
+++ b/src/Components/Samples/BlazorUnitedApp/App.razor
@@ -3,7 +3,7 @@
-
+
diff --git a/src/Components/Samples/BlazorUnitedApp/_Imports.razor b/src/Components/Samples/BlazorUnitedApp/_Imports.razor
index 1be7a7e9a5bf..8cacc98a9e57 100644
--- a/src/Components/Samples/BlazorUnitedApp/_Imports.razor
+++ b/src/Components/Samples/BlazorUnitedApp/_Imports.razor
@@ -3,6 +3,7 @@
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
+@using Microsoft.AspNetCore.Components.Endpoints
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.JSInterop
@using BlazorUnitedApp
diff --git a/src/Components/test/testassets/Components.TestServer/RazorComponents/App.razor b/src/Components/test/testassets/Components.TestServer/RazorComponents/App.razor
index 94a9a5a597e5..fba24956b11b 100644
--- a/src/Components/test/testassets/Components.TestServer/RazorComponents/App.razor
+++ b/src/Components/test/testassets/Components.TestServer/RazorComponents/App.razor
@@ -4,6 +4,7 @@
@using TestContentPackage.NotFound
@using Components.TestServer.RazorComponents
@using Microsoft.AspNetCore.Components
+@using Microsoft.AspNetCore.Components.Endpoints
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using System.Threading.Tasks
@@ -99,7 +100,7 @@
-
+
diff --git a/src/Components/test/testassets/Components.TestServer/RazorComponents/NamedFormContextNoFormContextApp.razor b/src/Components/test/testassets/Components.TestServer/RazorComponents/NamedFormContextNoFormContextApp.razor
index fc8a291d9821..cc1a416596bf 100644
--- a/src/Components/test/testassets/Components.TestServer/RazorComponents/NamedFormContextNoFormContextApp.razor
+++ b/src/Components/test/testassets/Components.TestServer/RazorComponents/NamedFormContextNoFormContextApp.razor
@@ -1,10 +1,11 @@
@using Components.TestServer.RazorComponents.Pages.Forms
+@using Microsoft.AspNetCore.Components.Endpoints
-
+
diff --git a/src/Components/test/testassets/Components.TestServer/RazorComponents/RemoteAuthenticationApp.razor b/src/Components/test/testassets/Components.TestServer/RazorComponents/RemoteAuthenticationApp.razor
index c8f89e587f8f..057376591785 100644
--- a/src/Components/test/testassets/Components.TestServer/RazorComponents/RemoteAuthenticationApp.razor
+++ b/src/Components/test/testassets/Components.TestServer/RazorComponents/RemoteAuthenticationApp.razor
@@ -1,9 +1,11 @@
-
+@using Microsoft.AspNetCore.Components.Endpoints
+
+
-
+
diff --git a/src/Components/test/testassets/Components.TestServer/RazorComponents/Root.razor b/src/Components/test/testassets/Components.TestServer/RazorComponents/Root.razor
index 9238fb858c7b..82bed6851f37 100644
--- a/src/Components/test/testassets/Components.TestServer/RazorComponents/Root.razor
+++ b/src/Components/test/testassets/Components.TestServer/RazorComponents/Root.razor
@@ -1,11 +1,12 @@
@using Components.TestServer.RazorComponents.Pages.Forms
+@using Microsoft.AspNetCore.Components.Endpoints
@using Microsoft.AspNetCore.Components.Web
-
+
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWebCSharp.1/Components/App.razor b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWebCSharp.1/Components/App.razor
index 347861a467ff..c7e72eb2f460 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWebCSharp.1/Components/App.razor
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWebCSharp.1/Components/App.razor
@@ -4,7 +4,7 @@
-
+
@*#if (SampleContent)
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWebCSharp.1/Components/_Imports.razor b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWebCSharp.1/Components/_Imports.razor
index 192e7b16edfe..ec70fa0106f3 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWebCSharp.1/Components/_Imports.razor
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWebCSharp.1/Components/_Imports.razor
@@ -1,5 +1,6 @@
@using System.Net.Http
@using System.Net.Http.Json
+@using Microsoft.AspNetCore.Components.Endpoints
@*#if (IndividualLocalAuth)
@using Microsoft.AspNetCore.Components.Authorization
##endif*@