A while ago, I wrote about Blazor Bootstrap, which is a Razor component library for Blazor applications that want to use Bootstrap as UI framework.

The other day, I was working on the Heading component, and wanted to make it possible to turn every Heading into an anchor link. This would allow you to easily link directly to each heading on the page. Here is quite a descriptive explanation of what an anchor link is.

An anchor link is a web link that allows users to leapfrog to a specific point on a website page. It saves them the need to scroll and skim read – and makes navigation easier.

Doesn’t sound too hard, does it? Just add an <a> element to the heading, and specify a unique ID as href, as shown below.

<h2 id="the-heading"><a href="#the-heading">The Heading</a></h2>

So it turns out that it unfortunately is not quite that easy. To make it easier for you to follow, I created a repository on GitHub with the solution to the problems described below. The sample application in the repository is also published on GitHub Pages at https://mikaberglund.github.io/anchor-link-in-blazor-application/


The problem with anchor links is that when you click on them, the page won’t scroll to the element you’ve specified in the link. Anchor links will always take you to the top of the front page of your application. This has to do with how routing is handled in Blazor and most other SPA applications as well. It’s definitely not just a problem with Blazor.

Luckily there is quite a simple solution. You just need to create your own AnchorLink component (or name it however you like) and use a little bit of JavaScript interop magic.

The AnchorLink Component

The AnchorLink component is built up of the AnchorLink.razor and the anchorLink.js files. The main responsibility of the Razor component is to examine the value of the href attribute and determine whether it is an anchor link. Anchor links starts with a hash (#). If it is an anchor link, then the default click action is prevented, and the scrollIntoView JavaScript function is called when the anchor is clicked using the injected JavaScript interop runtime.

The scrollIntoView JavaScript function supports the Razor component by scrolling the given element into view when the function is called.

Using the AnchorLink Component

When you have completed the AnchorLink component, you can use it in your application as a replacement for the default <a> element. Remember also to add a reference to the anchorLink.js file to the index.html template, so that the browser loads that file too.

You can use any standard attributes on the AnchorLink component as you would on an <a> element. Below are a few samples.

    The Table of Contents below demonstrate how
    you can use the <code>AnchorLink</code> component.
    You can also use it as a <AnchorLink href="...">normal link</AnchorLink>
    to point to any URI.
    <li><AnchorLink href="#chapter1">Chapter 1</AnchorLink></li>
    <li><AnchorLink href="#chapter2">Chapter 2</AnchorLink></li>
    <li><AnchorLink href="#chapter3">Chapter 3</AnchorLink></li>
<h2 id="chapter1">Chapter #1</h2>
    This is chapter #1.
<h2 id="chapter2">Chapter #2</h2>
    This is chapter #2.
<h2 id="chapter3">Chapter #3</h2>
    This is chapter #3. The source code to the <code>AnchorLink</code>
    component is available on <AnchorLink href="https://github.com/MikaBerglund/anchor-link-in-blazor-application" target="_blank">GitHub</AnchorLink>.


If you want to learn more about building components for your Blazor applications, I suggest you have a look at the Create and use AS.NET Core Razor components article. That will give you a very good overview of what’s possible.

And thanks to Chris Sainty, who pointed out some errors in this article, which I’ve now fixed.


Chris Sainty · December 28, 2019 at 15:33

Hi Mika,

I’ve just read your post but I have a concern. Part of your solution is to remove the base tag, this isn’t a good idea. The base tag is essential to routing in Blazor when the app doesn’t sit at the root of the site.

Given your example above, if you want to create an anchor link to #chapter-1 on the introduction page. If you construct your link like this: href=”/introduction/#chapter-1″ then use your custom component as you explain, then there is no need to remove the base tag and the solution should work in all scenarios.


    Mika Berglund · December 28, 2019 at 18:52

    Thanks for you comment, Chris!

    I know that you can build your anchor links by prefixing them with the page. However, ever since anchor links were invented, links targeting the same page have always been constructed with just href=”#chapter-1″, not “href=”[current page]#chapter-1″. That’s why I was going for a solution that would not require me to change the way I build anchor links, but create them in a way they have always been created.

    If you are not running your application from the root of the site, then you probably would need to specify folder name your application is running from as root, and not the default base=”/” anyway, right?

      Chris Sainty · December 28, 2019 at 21:06

      “However, ever since anchor links were invented, links targeting the same page have always been constructed with just href=”#chapter-1″, not “href=”[current page]#chapter-1″.”

      That’s true for traditional mult-page web applications but I wouldn’t agree for SPAs. Most SPA frameworks seem to have some quirk to deal with anchor links, but we could lose hours talking about all that! 🙂

      “If you are not running your application from the root of the site, then you probably would need to specify folder name your application is running from as root, and not the default base=”/” anyway, right?”

      That’s correct if your app was running from mydomain.com/blazor then you would need to set the base tags href to “/blazor/”. Essentially, Blazor’s routing system uses the base tags href value to know what links it should and should not intercept.

        Mika Berglund · December 29, 2019 at 10:02

        It’s not hours lost, it’s hours spent on learning about others’ viewpoints 😉

        Anyway, I will update the article to reflect this discussion. I’m currently working on publishing the demo application using GitHub Pages for the repository. There, the application will be running in a non-root folder, so I’ll need to put in the base href.

    Mika Berglund · December 28, 2019 at 18:59

    But you are right Chris. With the custom AnchorLink component, we don’t need to remove the base tag, since our custom component will prevent the default action anyway.

    Thank you for pointing this out. I’ll update the article to reflect this.

Troy Gerton · June 15, 2020 at 17:48

This is exactly what I was looking for. Thank you, Mika. I had to modify it to work inside a bootstrap accordion because the onclick event triggered the collapse/expand. This was solved by adding a parameter to AnchorLink.razor and implementing two-way binding on it. Works great! Following are snippets on how I handled it…
public bool Collapsed { get; set; }

public EventCallback CollapsedChanged { get; set; }

private async Task AnchorOnClickAsync()
if (!string.IsNullOrEmpty(this.targetId))
Collapsed = !Collapsed;
await CollapsedChanged.InvokeAsync(Collapsed);
// 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 this.JsInterop.InvokeVoidAsync(“anchorLink.scrollIntoView”, this.targetId);

And my anchor usage changed from this…
this.collapsed = !this.collapsed”>Reports

to this…

Good stuff. Thanks again…troy

    Mika Berglund · June 17, 2020 at 07:12

    Great that you got it sorted.

Troy Gerton · June 15, 2020 at 17:52

Oops. This blog didn’t like my markup.

<!– this.collapsed = !this.collapsed”>Reports–>

to this…


Troy Gerton · June 15, 2020 at 17:53

Thanks for the solution. Exactly what I needed.

Lukas · June 16, 2020 at 00:48

I have a problem. When I add these lines in my code
I see the inscription on my website “AnchorLink” above my list item.
When i go to ctrl+Shift+I at Google Chrome and i choose this inscription i can see:
On your page i can see only Chapter 1
Could you tell me why?

    Mika Berglund · June 17, 2020 at 07:11

    It’s pretty hard to say without code to look at.

Leave a Reply

Avatar placeholder

Your email address will not be published.