Blazor Anchor Tag Scroll To
In this article I will go over an issue with Blazor applications and scrolling to a hash anchor on the current page.
The Problem
When your using ASP.NET Core Blazor and want to navigate to an on page anchor, sadly requires a little bit of JavaScript to handle this scenario. I believe the reason for this is because a Blazor application will watch all routing events, even if its an on page navigation. To also get around this requires attributes on the Razor anchor tag to prevent the default behavior of the link.
To helpĀ alleviateĀ this issue I crafted a small snippet of JavaScript and a Razor component that helps with the creation of links, allowing for them to scroll to the hash on your current page or navigate by default behavior. The JavaScript will take in the element's id and scroll it into view, and update the window.location.hash to the passed in element id. The below Razor Component helps encapsulate that necessary logic calling into the JavaScript and preventing default behavior of the anchor tag.
function scrollIntoView(elementId) {
var elem = document.getElementById(elementId);
if (elem) {
elem.scrollIntoView();
window.location.hash = elementId;
}
}
scrollIntoView
, provided by JavaScript, if necessary.
<a @attributes="Attributes"
@onclick="AnchorOnClickAsync"
@onclick:preventDefault="@preventDefault">
@ChildContent
</a>
namespace Components.AnchorLink
{
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
public partial class AnchorLink
: ComponentBase
{
[Parameter(CaptureUnmatchedValues = true)]
public IDictionary<string, object> Attributes { get; set; } = new Dictionary<string, object>();
[Parameter]
public RenderFragment ChildContent { get; set; } = null!;
[Inject]
protected IJSRuntime JSRuntime { get; set; } = null!;
private string targetId = string.Empty;
private bool preventDefault = false;
protected override void OnParametersSet()
{
if (Attributes.ContainsKey("href"))
{
// If the href attribute has been specified, we examine the value of it. If if starts with '#'
// we assume the rest of the value contains the ID of the element the link points to.
var href = $"{Attributes["href"]}";
if (href.StartsWith("#"))
{
// If the href contains an anchor link we don't want the default click action to occur, but
// rather take care of the click in our own method.
targetId = href[1..];
preventDefault = true;
}
}
base.OnParametersSet();
}
private async Task AnchorOnClickAsync()
{
if (!string.IsNullOrEmpty(targetId))
{
// If the target ID has been specified, we know this is an anchor link that we need to scroll
// to, so we call the JavaScript method to take care of this for us.
await JSRuntime.InvokeVoidAsync(
"scrollIntoView",
targetId
);
}
}
}
}