While Blazor works well for developing web applications, in some scenarios you will want to leverage some browser capabilities that Blazor still doesn’t have access or in some cases you want to take advantage on the functionality of some JavaScript libraries. For those and more reasons Blazor frameworks lets you invoke JavaScript functions from .Net methods.

Blazor offers us an abstraction called IJSRuntime. With it we can invoke a JavaScript method and we can send arguments as well.

We fist need to structure the JavaScript code and located in the proper place so its available when we want to call it. Based on the Blazor documentation depending on what type of Blazor project you are running you should place the JavaScript code in one of the following places.

Inside  wwwroot/index.html (Blazor client-side) or Pages/_Host.cshtml (Blazor server-side) 

Instead of pasting the actual JavaScript directly we will right it on a file and then including it like any other JavaScript file. Our JS function will receive a text and assign it to an element.

  window.Tools = {
    SetText:  function (newText) {
            console.log(newText);
document.getElementById("title").innerHTML = newText;
        return newText;
    }
};

We will include out Javascript function

wwwroot/index.html (Blazor client-side):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Blazor Sample</title>
    <base href="/" />
    <link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
    <link href="css/site.css" rel="stylesheet" />
</head>
<body>
    <app>Loading...</app>

    <script src="_framework/blazor.webassembly.js"></script>
    <script src="myJsInteropFunctions.js" ></script>
</body>
</html>

Pages/_Host.cshtml (Blazor server-side):

@page "/"
@namespace blazorsample.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<!DOCTYPE html>
<html>
<head>
    :
    :
</head>
<body>
    <app>@(await Html.RenderComponentAsync<App>())</app>

    <script src="_framework/blazor.server.js"></script>
<script src="myJsInteropFunctions.js" ></script>
</body>
</html>
NOTE: Don't place a <script> tag in a component file because the <script> tag can't be updated dynamically. 

In order to call a JavaScript function from .Net, we will use the IJRuntime abstraction. Blazor offers a couple of ways to use the IJRuntime:

  • Inject the IJRuntime abstraction into the Razor component
@page "/"
@inject IJSRuntime JSRuntime
<h1 id="title">Hello, world!</h1>

Welcome to your new app.


@code{
}
  • You can also inject the IJSRuntime in a .cs class:
using System.Threading.Tasks;

namespace BlazorJSInterop.Shared.Services
{
    public class JSSerivce
    {
        private readonly IJSRuntime _jsRuntime;
        public JSSerivce(IJSRuntime jsRuntime)
        {
            _jsRuntime = jsRuntime;
        }

        public Task<string> SetText(string text)
        {
            return _jsRuntime.InvokeAsync<string>(
            "SetText",
            text);
        }
    }
}
  • For dynamic content generation with BuilderRenderTree, use the [Inject]attribute
@page "/counter"

<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="@IncrementCount">Click me</button>
@code {
    [Inject]
    IJSRuntime JSRuntime { get; set; }
    int currentCount = 0;
    void IncrementCount()
    {
        currentCount++;
    }
}

To start using the IJSRuntime we will call our JavaScript function when the app loads. Keep in mind that IJSRuntime must be call after the component have rendered. For example, in this case we will invoke the JS function in the OnAfterRenderd lifecycle of the component

@page "/"
@inject IJSRuntime JSRuntime
<h1 id="title">Hello, world!</h1>
Welcome to your new app.
@code{
    protected override void OnAfterRender()
    {
            JSRuntime.InvokeAsync<object>(
                "SetText", "OnAfterRender was Triggered");
    }
}

Once the component is finish rendering it will set the element inner html to ‘OnAfterRender was Triggered’, we can also reference an element and send it to the JS function. We add the nee parameter to the JavaScript function

window.Tools = {
    SetText:  function (newText, elemntRef) {
            console.log(newText);
            elemntRef.innerHTML = newText;
        return newText;
    }
};
<h1 @ref="title">Hello, world!</h1>
@code{
ElementRef title;
    protected override void OnAfterRender()
    {
            JSRuntime.InvokeAsync<object>(
                "SetText", "OnAfterRender was Triggered", title);
    }
}
NOTE:
For server-side apps:
•	Multiple user requests are processed by the server-side app. Don't call JSRuntime.Current in a component to invoke JavaScript functions.
•	Inject the IJSRuntime abstraction and use the injected object to issue JavaScript interop calls.
•	While a Blazor app is prerendering, calling into JavaScript isn't possible because a connection with the browser hasn't been established. For more information, see the Detect when a Blazor app is prerendering section.

Blazor also offer the capability to call C# .Net method from a JavaScript function. To invoke a static .Net method from JavaScript, use the DotNet.invokeMethod or DotNet.invokeMethodAsync functions. To test this first we will add a JavaScript function, this function will call our .Net method.

window.Tools = {
    SetText:  function (newText, elemntRef) {
            console.log(newText);
            elemntRef.innerHTML = newText;
        return newText;
    },
    csharpMethod: function (){
    DotNet.invokeMethodAsync('BlazorJSInterop', 'ReturnArrayAsync')
        .then(data => {
            data.push("Blazor");
            console.log(data);
        });
}
};

Now we will create the .Net method to be called

@page "/counter"

<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="@IncrementCount">Click me</button>

<button class="btn btn-primary"  @onclick="Tools.csharpMethod()">C# Mehtod</button>

@code {
    [Inject]
    IJSRuntime JSRuntime { get; set; }
    int currentCount = 0;
    void IncrementCount()
    {
        currentCount++;
    }
    [JSInvokable]
    public static Task<string[]> ReturnArrayAsync()
    {
        return Task.FromResult(new string[] { "Nativo", "Plus", "MedConex" });
    }
}

The new button will trigger a JavaScript function that will invoke a .Net method. To keep it simple we will get a string array from the .Net method and will make the JavaScript add a new string to the array and then log the array in the console.

You can use this knowledge to wrap any JavaScript function that may need, you can even create your own .Net services that take advantage of a JavaScript library. If you wich to put Blazor JSInterop to the test you can head out to the Repository on github.