Blazor Built-in Components Created: 04 Feb 2026 Updated: 04 Feb 2026

ElementReference in Blazor

ElementReference is a struct in Blazor that provides direct access to HTML DOM elements from C# code. Normally, Blazor abstracts DOM interaction and doesn't allow direct DOM manipulation. However, certain scenarios require direct access to DOM elements:

  1. ✅ Setting focus on input elements
  2. ✅ Drawing on canvas elements
  3. ✅ Playing video/audio
  4. ✅ Integration with third-party JavaScript libraries
  5. ✅ Getting element dimensions/position

Basic Syntax

To create a reference to an HTML element, use the @ref directive:

<input @ref="myInput" />

@code {
private ElementReference myInput;
}

⚠️ Important Rule: OnAfterRender

ElementReference is only valid after the component has been rendered. Therefore, it must be used in the OnAfterRenderAsync lifecycle method:

@code {
private ElementReference myInput;

protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
// Element now exists in DOM, reference can be used
await myInput.FocusAsync();
}
}
}
Note: Using ElementReference before the component renders will result in an invalid reference.

Example 1: Auto Focus (Built-in FocusAsync)

Starting with .NET 5, the built-in FocusAsync() extension method allows you to set focus without needing JavaScript:

<input @ref="searchInput" placeholder="Search..." />

@code {
private ElementReference searchInput;

protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await searchInput.FocusAsync();
}
}
}

Example 2: Focus on Button Click

<input @ref="emailInput" type="email" placeholder="Enter your email" />
<button @onclick="FocusEmailAsync">Go to Email</button>

@code {
private ElementReference emailInput;

private async Task FocusEmailAsync()
{
await emailInput.FocusAsync();
}
}

Example 3: Multiple Element References (Array)

When you need to manage multiple elements, you can use an array of ElementReference:

<input @ref="inputs[0]" placeholder="First Name" />
<input @ref="inputs[1]" placeholder="Last Name" />
<input @ref="inputs[2]" placeholder="Email" />

<button @onclick="() => FocusAsync(0)">Focus First Name</button>
<button @onclick="() => FocusAsync(1)">Focus Last Name</button>
<button @onclick="() => FocusAsync(2)">Focus Email</button>

@code {
private ElementReference[] inputs = new ElementReference[3];

private async Task FocusAsync(int index)
{
await inputs[index].FocusAsync();
}
}

Example 4: Reading Values with JavaScript Interop

You can pass ElementReference to JavaScript functions using IJSRuntime:

Razor Component:

@inject IJSRuntime JS

<input @ref="valueInput" placeholder="Type something..." />
<button @onclick="GetValueAsync">Read Value</button>
<p>Value: @readValue</p>

@code {
private ElementReference valueInput;
private string readValue = string.Empty;

private async Task GetValueAsync()
{
readValue = await JS.InvokeAsync<string>("getElementValue", valueInput);
}
}

JavaScript (elementReference.js):

window.getElementValue = (element) => {
return element.value || '';
};

Example 5: Measuring Element Dimensions

Razor Component:

@inject IJSRuntime JS

<div @ref="sizeElement" style="width: 300px; height: 150px; border: 1px solid #ccc;">
Content to measure
</div>
<button @onclick="GetDimensionsAsync">Measure Dimensions</button>
<p>@dimensionText</p>

@code {
private ElementReference sizeElement;
private string dimensionText = string.Empty;

private async Task GetDimensionsAsync()
{
var dimensions = await JS.InvokeAsync<ElementDimensions>(
"getElementDimensions", sizeElement);
dimensionText = $"Width: {dimensions.Width}px, Height: {dimensions.Height}px";
}

private record ElementDimensions(double Width, double Height);
}

JavaScript:

window.getElementDimensions = (element) => {
const rect = element.getBoundingClientRect();
return { width: rect.width, height: rect.height };
};

Example 6: Scroll Control

Razor Component:

@inject IJSRuntime JS

<div @ref="scrollContainer" style="height: 200px; overflow: auto; border: 1px solid #ccc;">
@for (int i = 1; i <= 100; i++)
{
<p>Line @i</p>
}
</div>
<button @onclick="ScrollTopAsync">Scroll to Top</button>
<button @onclick="ScrollBottomAsync">Scroll to Bottom</button>

@code {
private ElementReference scrollContainer;

private async Task ScrollTopAsync()
{
await JS.InvokeVoidAsync("scrollToPosition", scrollContainer, 0);
}

private async Task ScrollBottomAsync()
{
await JS.InvokeVoidAsync("scrollToBottom", scrollContainer);
}
}

JavaScript:

window.scrollToPosition = (element, position) => {
element.scrollTop = position;
};

window.scrollToBottom = (element) => {
element.scrollTop = element.scrollHeight;
};

Example 7: Working with Canvas

Razor Component:

@inject IJSRuntime JS

<canvas @ref="canvasElement" width="400" height="200" style="border: 1px solid black;"></canvas>
<button @onclick="DrawRectangleAsync">Draw Rectangle</button>

@code {
private ElementReference canvasElement;

private async Task DrawRectangleAsync()
{
await JS.InvokeVoidAsync("drawRectangle", canvasElement);
}
}

JavaScript:

window.drawRectangle = (canvas) => {
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'blue';
ctx.fillRect(50, 50, 150, 100);
};

Common Pitfalls

❌ Don't Do This✅ Do This Instead
Use in OnInitializedUse in OnAfterRenderAsync
Use during prerenderingCheck firstRender flag
Modify DOM directly without Blazor knowingKeep Blazor state synchronized
Assume reference is valid immediatelyWait for render completion

Prerendering Considerations

When using Server-Side Rendering (SSR) or prerendering, ElementReference operations will fail because there's no browser DOM. Always wrap your code:

@code {
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
// Safe to use ElementReference here
await myElement.FocusAsync();
}
}
}

Summary Table

PropertyDescription
Declaration@ref="elementRef"
TypeElementReference (struct)
ValidityAfter render (OnAfterRenderAsync)
Built-in MethodFocusAsync() (.NET 5+)
JS InteropIJSRuntime.InvokeAsync("funcName", elementRef)

Best Practices

  1. Always use OnAfterRenderAsync - ElementReference is only valid after rendering
  2. Check firstRender - Avoid unnecessary operations on subsequent renders
  3. Use built-in FocusAsync() - No need for JavaScript for simple focus operations
  4. Handle prerendering - Be aware that ElementReference won't work during SSR
  5. Keep references minimal - Only create references when truly needed


Share this lesson: