Help us improve
Share bugs, ideas, or general feedback.
From dotnet-blazor
Guides Blazor JavaScript interop for calling JS from .NET via IJSRuntime and .NET from JS via JSInvokable, including collocated JS modules and best practices.
npx claudepluginhub markus41/claude --plugin dotnet-blazorHow this skill is triggered — by the user, by Claude, or both
Slash command
/dotnet-blazor:blazor-js-interopThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
```csharp
Building Blazor components. Lifecycle, state management, JS interop, EditForm validation, QuickGrid.
Explains Blazor component model: render modes (SSR, Interactive Server/WebAssembly/Auto), lifecycle methods, parameters, EventCallbacks, and communication via cascading values. For .NET web app developers.
Guides embedding web content in .NET MAUI apps using HybridWebView with bidirectional JS-C# interop, serialization setup, common gotchas, and NativeAOT trimming.
Share bugs, ideas, or general feedback.
@inject IJSRuntime JS
@code {
private async Task ShowAlert()
{
await JS.InvokeVoidAsync("alert", "Hello from Blazor!");
}
private async Task<string> GetValue()
{
return await JS.InvokeAsync<string>("localStorage.getItem", "key");
}
// With element reference
private ElementReference _inputRef;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await JS.InvokeVoidAsync("focusElement", _inputRef);
}
}
}
// Static .NET method
[JSInvokable]
public static Task<string> GetDataFromDotNet()
{
return Task.FromResult("Hello from .NET!");
}
// Instance method
private DotNetObjectReference<MyComponent>? _dotNetRef;
protected override void OnInitialized()
{
_dotNetRef = DotNetObjectReference.Create(this);
}
[JSInvokable]
public void HandleJsCallback(string data)
{
_message = data;
StateHasChanged();
}
public void Dispose() => _dotNetRef?.Dispose();
// Call static method
const result = await DotNet.invokeMethodAsync('MyApp', 'GetDataFromDotNet');
// Call instance method
dotNetRef.invokeMethodAsync('HandleJsCallback', 'data from JS');
Components/Pages/
├── Map.razor
├── Map.razor.cs
└── Map.razor.js ← Collocated JS module
// Map.razor.js
export function initializeMap(element, options) {
const map = new google.maps.Map(element, options);
return map;
}
export function dispose() {
// Cleanup
}
// Map.razor.cs
private IJSObjectReference? _module;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
_module = await JS.InvokeAsync<IJSObjectReference>(
"import", "./Components/Pages/Map.razor.js");
await _module.InvokeVoidAsync("initializeMap", _mapElement, _options);
}
}
public async ValueTask DisposeAsync()
{
if (_module is not null)
{
await _module.InvokeVoidAsync("dispose");
await _module.DisposeAsync();
}
}
.razor.js modules over global scriptsIJSObjectReference and DotNetObjectReferenceOnAfterRenderAsync (DOM must exist)IJSRuntime in Server mode, IJSInProcessRuntime only in WASMJSDisconnectedException in Blazor Server for graceful cleanup