About JavaScript Location

Load a script in the <head> tag

<head>
    <script src="js/first.js"></script>
    <script>
      window.jsMethod = (methodParameter) => {
        ...
      };
    </script>
</head>

Load a script in the <body> tag

<body>
    <script src="js/first.js"></script>
    <script>
      window.jsMethod = (methodParameter) => {
        ...
      };
    </script>
</body>

Colocate with the component

Component: CountComponent.razor
Component: CountComponent.razor.cs
Style: CountComponent.razor.css
Script: CountComponent.razor.js

Call JS from .NET

Create an app.js file under wwwroot

function helloWorld() {
    alert('Hello World');
}

function add(a, b) {
    return a + b;
}

Include the JS file in App.razor

Script inclusion in the current web project

<head>
    <script src="@Assets["app.js"]"></script>
</head>

If an RCL component library is used

<head>
    <script src="_content/LibraryName/app.js"></script>
</head>

Call JS methods from a .NET component

@inject IJSRuntime JS

<button class="btn btn-primary" @onclick="SayHello">SayHello</button>
<button class="btn btn-primary" @onclick="Add">Add</button>
<p>Current count: @result</p>

@code {

    private int result = 0;

    private async Task SayHello()
    {
        await JS.InvokeVoidAsync("helloWorld");
    }

    private async Task Add()
    {
        result = await JS.InvokeAsync<int>("add", result, 1);
        StateHasChanged();
    }
}

Module-based JS files

export function helloWorld() {
    alert('Hello World');
}

export function add(a, b) {
    return a + b;
}

Write the following code in the MyComponent.razor component

@inject IJSRuntime JS
@implements IAsyncDisposable

@code {
    private IJSInProcessObjectReference? module;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            var jsInProcess = (IJSInProcessRuntime)JS;
            module = await JS.InvokeAsync<IJSInProcessObjectReference>("import", "./path/to/MyComponent.razor.js");
            var value = module.Invoke<string>("javascriptFunctionIdentifier");
        }
    }

    async ValueTask IAsyncDisposable.DisposeAsync()
    {
        try
        {
            if (module is not null)
            {
                await module.DisposeAsync();
            }
        }
        catch (JSDisconnectedException)
        {
        }
    }
}

<div @ref="divElement" style="margin-top:2000px">
    Set value via JS interop call: <strong>@scrollPosition</strong>
</div>
@code {
    private ElementReference divElement;
    private int scrollPosition;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            var jsInProcess = (IJSInProcessRuntime)JS;
            var module = await jsInProcess.InvokeAsync<IJSInProcessObjectReference>("import", "./path/to/MyComponent.razor.js");
            scrollPosition = await module.InvokeAsync<int>("getScrollPosition", divElement);
        }
    }
}

Two static methods are provided

DotNet.invokeMethodAsync('{ASSEMBLY NAME}', '{.NET METHOD ID}', {ARGUMENTS});
DotNet.invokeMethod('{ASSEMBLY NAME}', '{.NET METHOD ID}', {ARGUMENTS});    

Provide a static method in the C# component

@code {
    [JSInvokable]
    public static Task{<T>} {.NET METHOD ID}()
    {
        ...
    }
}

You can specify a parameter to change the method name

[JSInvokable("DifferentMethodName")]
public static Task{<T>} {.NET METHOD ID}()
{
    ...
}

Call .NET methods via dotNetHelper

A .NET instance is passed to JS by reference by wrapping it in a DotNetObjectReference and calling Create on it.

@inject IJSRuntime JS
@implements IAsyncDisposable
@code {
    private DotNetObjectReference<MyComponent>? dotNetHelper;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            dotNetHelper = DotNetObjectReference.Create(this);
            await JS.InvokeVoidAsync("jsFunction", dotNetHelper);
        }
    }

    public async ValueTask DisposeAsync()
    {
        if (dotNetHelper is not null)
        {
            await dotNetHelper.DisposeAsync();
        }
    }
}