Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scroll to specified part of page when clicking top navigation link in Blazor

Tags:

html

c#

css

blazor

How can I make a simple "jump to" part of already loaded page in Blazor? Like this in HTML:

<a href="#contact">Contact us</a>
...
<section id="contact">

Ideally I also want to have it smooth scroll down to this section. Thought I would try to solve this with CSS, but maybe not possible?

like image 988
johajan Avatar asked Mar 15 '19 16:03

johajan


People also ask

How do I scroll to the top position in a Blazor page?

In Blazor, you can call a JavaScript method using JavaScript interop to scroll the page to the top position. In the following code, the button event triggers when the button is clicked and scrolls to the page top.

How do I scroll to a specific element?

The scrollTo method: The scrollTo() is used to scroll to the specified element in the browser.

Which tag in a Blazor page generates a clickable anchor link?

The anchor tag helper targets the HTML anchor ( <a> ) tag which is used to generate relative links from the values passed to various custom attributes.

How do you add a section to a scroll in HTML?

By using the <Style> tag, we will add the scroll options in HTML Page itself.


2 Answers

I've solved this by using a button and then writing some inline Javascript in the markup. You can generalize this to a Blazor component for bonus points!

<button type="button" onclick="document.getElementById('contact').scrollIntoView({behavior:'smooth'})">Contact us</button>
...
<section id="contact">
like image 132
Aaron Hudon Avatar answered Sep 21 '22 15:09

Aaron Hudon


What you need is the hashed routes features of Blazor. But, alas, no such features do exist yet. I'd suggest you use JSIterop to perform this task: Create a JavaScript that performs the navigation, and pass it an ElementRef object.

Hope this helps...

Edit: The following is an adaptation of the best workaround solution I've found in Github...

Ordinarily, when you click the link to contact, you get redirected to the route http://localhost:5000/mypage#contact, but will be at the top of the page. The fragment of the route is not used for selection of a specific HTML element.

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:

mypage.cshtml:

         @page "/mypage"
    @inject Microsoft.AspNetCore.Components.Services.IUriHelper UriHelper

    <nav>

        <a href="#contact">contact</a>


    </nav>


    <section>
        <h2 id="contact">contact</h2>

    </section>


@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();
    }
}

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>

Note: If you're using Blazor version .9.0, you should inject the IJSRuntime Please, let me know if this solution works for you...

like image 25
enet Avatar answered Sep 18 '22 15:09

enet