plugins/dotnet-blazor/skills/blazor-js-interop/SKILL.md
JavaScript interop in Blazor for calling JS from .NET and .NET from JS
npx skillsauth add markus41/claude blazor-js-interopInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
@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 cleanupdevelopment
Enhanced plan-authoring skill with Pre-Writing context gathering, task metadata, non-TDD templates, Red Flags, telemetry, and an automated plan linter. Use when you have a spec or requirements for a multi-step task, before touching code.
tools
Documentation intelligence engine with graph-based API docs, algorithm library, and drift detection
tools
Ultraplan cloud planning — kick off a plan in the cloud from your terminal, review and revise in the browser, then execute remotely or send back to CLI
tools
--- name: mcp description: Configure MCP servers for Claude Code — stdio vs HTTP, authentication, Tools/Resources/Prompts distinction, channels (CI webhook, mobile relay, Discord bridge, fakechat), and cost of always-loaded tools. Use this skill whenever adding an MCP server, debugging connection issues, choosing between MCP Tools vs Prompts vs Resources, installing channel servers, or managing .mcp.json. Triggers on: "MCP server", "mcp config", "add Obsidian MCP", "install context7", "channels"