There are a couple of ways to set focus on an element the Blazor native way. Because a Blazor App is a SPA, when user navigate to a page, it just load a part of page as needed. That why autofocus attribute won’t work. Also, you can’t embed a <script> tag in any where to do focus or anything else.
With JavaScript Support
Normally, I have a javascript file named blazor_support.js
. It contains many helper functions that not supported in Blazor native. This file should be located in wwwroot/js/blazor_support.js
.
window.Js = {
focus: function (element) {
element.focus();
}
}
Next, I embed the file by entering the <script> tag directly in the Host.chtml file, just above the </body> tag.
<script src="js/blazor_support.js"></script>
Now, write an extension file, I’ve added the extension file named JsFunctions.cs
:
public static async Task FocusAsync(this ElementReference elementRef,
IJSRuntime jsRuntime)
{
await jsRuntime.InvokeVoidAsync("Js.focus", elementRef);
}
Then in the razor page (or component), inject the IJSRuntime
, Add an ElementReference
and tie it to the element you want to focus.
@page "/myform"
@inject IJSRuntime JSRuntime
@using JsFunctions
<input @ref="username" />
<button @onclick="SetFocusAsync">Set focus on username</button>
@code {
private ElementReference username;
public async Task SetFocusAsync()
{
await username.FocusAsync(JSRuntime);
}
}
Where will you call focus?
Normally, you will do focus in OnAfterRenderAsync
. Invoke a javascript in OnInitializedAsync
will cause a runtime exception because the rendering has not completed.
protected async override Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await SetFocusAsync();
}
}
But it does not work sometime 🙁
In a real life, you will find that way does not work sometime. OnAfterRenderAsync
does not mean HTML elements are ready, you need to wait a bit to let browser render inputs and ready to receive the focus. Now, refine the focus function:
window.Js = {
focus: function (element) {
setTimeout(() => { element.focus(); }, 250);
}
}