JavaScript Interop in ASP.NET Core Blazor

Blazor enables seamless communication between your .NET C# code and JavaScript. This is crucial for leveraging existing JavaScript libraries, accessing browser APIs not directly exposed to .NET, or performing DOM manipulations when necessary.

Calling JavaScript Functions from .NET

To call a JavaScript function from your Blazor component, you use the IJSRuntime service. This service is injected into your component, and its InvokeAsync method is used to execute JavaScript code.

Basic Invocation

You can invoke a JavaScript function by providing its name and any arguments.

Ensure the JavaScript function is available in the global scope or within a module that has been loaded.

Example in a Blazor component (.razor file):


@inject IJSRuntime JSRuntime

<button @onclick="CallJavaScriptAlert">Show Alert</button>

@code {
    private async Task CallJavaScriptAlert()
    {
        await JSRuntime.InvokeVoidAsync("alert", "Hello from Blazor!");
    }
}
            

Corresponding JavaScript (e.g., in wwwroot/js/site.js):


function alert(message) {
    window.alert(message);
}
            

Invoking JavaScript with Return Values

If your JavaScript function returns a value, you can use InvokeAsync with a generic type parameter to capture the result.

Example in a Blazor component:


@inject IJSRuntime JSRuntime

<button @onclick="GetBrowserInfo">Get Browser Info</button>
<p>Browser Name: @browserName</p>

@code {
    private string browserName = "N/A";

    private async Task GetBrowserInfo()
    {
        browserName = await JSRuntime.InvokeAsync<string>("getBrowserName");
    }
}
            

Corresponding JavaScript:


function getBrowserName() {
    return navigator.appName;
}
            

Invoking JavaScript from Modules

For better organization, you can load JavaScript as modules. Use JSRuntime.InvokeAsync with the '@' prefix to refer to module imports.

Example in a Blazor component:


@inject IJSRuntime JSRuntime
@inject NavigationManager NavigationManager

<button @onclick="LogToConsole">Log to Console</button>

@code {
    private async Task LogToConsole()
    {
        await JSRuntime.InvokeVoidAsync("eval", @"
            import('/js/module.js').then(module => {
                module.logMessage('Logged from Blazor via module!');
            });
        ");
    }
}
            

Corresponding JavaScript (e.g., in wwwroot/js/module.js):


export function logMessage(message) {
    console.log(message);
}
            
Make sure to include the necessary JavaScript files in your index.html or _Host.cshtml.

Calling .NET Methods from JavaScript

Blazor also allows you to call .NET methods from JavaScript. This is achieved using callbacks registered with the .NET runtime.

Registering Callbacks

You can use DotNet.invokeMethodAsync from JavaScript to call a static or instance method on a .NET object.

Example in a Blazor component:


@inject IJSRuntime JSRuntime
@implements IDisposable

<button @onclick="RegisterCallback">Register Callback</button>
<p>Callback Result: @callbackResult</p>

@code {
    private string callbackResult = "Waiting for JS...";
    private DotNetObjectReference<MyComponent> dotnetRef;

    protected override void OnInitialized()
    {
        dotnetRef = DotNetObjectReference.Create(this);
    }

    private async Task RegisterCallback()
    {
        await JSRuntime.InvokeVoidAsync("registerDotNetCallback", dotnetRef);
    }

    [JSInvokable]
    public void ReceiveMessageFromJs(string message)
    {
        callbackResult = message;
        StateHasChanged(); // Ensure UI updates
    }

    public void Dispose()
    {
        dotnetRef?.Dispose();
    }
}
            

Corresponding JavaScript:


window.registerDotNetCallback = function(dotNetObjectReference) {
    // Simulate a delay before calling back
    setTimeout(() => {
        dotNetObjectReference.invokeMethodAsync('ReceiveMessageFromJs', 'Hello from JavaScript!');
    }, 1000);
};
            

Using DotNetObjectReference

The DotNetObjectReference is essential for passing an instance of a Blazor component to JavaScript so that JavaScript can invoke methods on that specific instance.

Remember to dispose of DotNetObjectReference instances to prevent memory leaks.

Working with the DOM

While Blazor's component model handles most UI updates, there might be scenarios where direct DOM manipulation is needed. JavaScript interop is the way to achieve this.

Example: Focusing an input element:


@inject IJSRuntime JSRuntime
@ref FocusInput

<input type="text" id="myInput" />
<button @onclick="FocusElement">Focus Input</button>

@code {
    private ElementReference FocusInput;

    private async Task FocusElement()
    {
        await JSRuntime.InvokeVoidAsync("focusElement", FocusInput);
    }
}
            

Corresponding JavaScript:


function focusElement(element) {
    element.focus();
}
            

Best Practices

This section provides a comprehensive overview of JavaScript interop in Blazor, enabling you to bridge the gap between .NET and browser functionalities effectively.