-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Description
Describe the bug
I cannot use an html anchor to navigate to a specific html element of a page.
To Reproduce
Steps to reproduce the behavior:
Given there is a Blazor page that looks like the following:
@layout MainLayout
@page "/foo"
<nav>
<!-- One version I've tried -->
<a href="#bar">Bar</a>
<!-- Another version I've tried -->
<NavLink href="#bar">Bar</NavLink>
@* ... *@
</nav>
@* ... *@
<section>
<h2 id="bar">Bar</h2>
@* ... *@
</section>
When I click the link to Bar, i get redirected to the route http://localhost:5000/foo#bar
, but will be at the top of the page. The fragment of the route is not used for selection of a specific HTML element.
Expected behavior
The browser should scroll down to the proper element, as specified by the Element Selector.
In cases where the fragment of the URL is used for other purposes, ie. for OAuth, it should be possible to overwrite the default Blazor router behavior. The behavior should be set on a per-page and per-app level.
Workaround
The proposed workaround does not work, since the browser crashes and is only for illustration.
The current workaround is to write explicit code that interprets the URL. In the example above, we could use a little bit of JavaScript and then call that from our Blazor code:
<!-- in index.html -->
<script>
window.scrollToElementId = (elementId) => {
console.info('scrolling to element', elementId);
var element = document.getElementById(elementId);
if(!element)
{
console.warn('element was not found', elementId);
return false;
}
element.scrollIntoView();
return true;
}
</script>
@inject Microsoft.AspNetCore.Components.Services.IUriHelper UriHelper
@functions {
protected override void OnInit()
{
NavigateToElement();
UriHelper.OnLocationChanged += OnLocationChanges;
}
private void OnLocationChanges(object sender, string location) => NavigateToElement();
private void NavigateToElement()
{
var url = UriHelper.GetAbsoluteUri();
var fragment = new Uri(url).Fragment;
if(string.IsNullOrEmpty(fragment))
{
return;
}
var elementId = fragment.StartsWith("#") ? fragment.Substring(1) : fragment;
if(string.IsNullOrEmpty(elementId))
{
return;
}
ScrollToElementId(elementId);
}
private static bool ScrollToElementId(string elementId)
{
return JSRuntime.Current.InvokeAsync<bool>("scrollToElementId", elementId).GetAwaiter().GetResult();
}
}
Additional context
blazor 0.8.0-preview-19104-04
.NET Core SDK (reflecting any global.json):
Version: 3.0.100-preview-010184
Commit: c57bde4593
Runtime Environment:
OS Name: Windows
OS Version: 10.0.17763
OS Platform: Windows
RID: win10-x64
Base Path: C:\Program Files\dotnet\sdk\3.0.100-preview-010184\
Host (useful for support):
Version: 3.0.0-preview-27324-5
Commit: 63a01b08e5
.NET Core SDKs installed:
2.1.600-preview-009426 [C:\Program Files\dotnet\sdk]
3.0.100-preview-010184 [C:\Program Files\dotnet\sdk]
.NET Core runtimes installed:
Microsoft.AspNetCore.All 2.1.6 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.App 2.1.6 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 3.0.0-preview-19075-0444 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 2.1.6 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 3.0.0-preview-27324-5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.WindowsDesktop.App 3.0.0-preview-27325-3 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]