Skip to main content

Blazor Auto Complete

Blazor Bootstrap autocomplete component is a textbox that offers the users suggestions as they type from the data source. And it supports client-side and server-side filtering.

Parameters

NameTypeDefaultRequiredDescriptionAdded Version
DataProviderAutoCompleteDataProviderDelegate<TItem>null✔️Gets or sets the data provider.0.4.0
DisabledboolfalseGets or sets the disabled state.0.4.0
EmptyTextstringNo records found.Gets or sets the empty text.1.10.2
LoadingTextstringLoading...Gets or sets the loading text.1.10.2
PlaceholderstringnullGets or sets the placeholder.0.4.0
PropertyNamestringnull✔️Gets or sets the property name.0.4.0
SizeAutoCompleteSizeAutoCompleteSize.DefaultGets or sets the autocomplete size.0.4.0
StringComparisonStringComparisonStringComparison.OrdinalIgnoreCaseGets or sets the StringComparison.0.4.1
StringFilterOperatorStringFilterOperatorStringFilterOperator.ContainsGets or sets the string filter operator.0.4.1
ValuestringnullGets or sets the value.0.4.0
ValueExpressionexpressionnullAutoComplete value expression.0.4.0

Methods

NameReturnsDescriptionAdded Version
Disable()voidDisables autocomplete.0.4.0
Enable()voidEnables autocomplete.0.4.0
RefreshDataAsync()TaskRefresh the autocomplete data.0.4.0
ResetAsync()TaskResets the autocomplete selection.0.4.0

Events

NameDescriptionAdded Version
OnChangedThis event fires immediately when the autocomplete selection changes by the user.0.4.0
ValueChangedThis event fires on every user keystroke that changes the textbox value.0.4.0

Keyboard Navigation

Blazor Bootstrap autocomplete component supports the following keyboard shortcuts to initiate various actions.

KeyDescriptionAdded Version
EscCloses the popup list when it is in an open state.1.3.1
Up arrowFocuses on the previous item in the list.1.3.1
Down arrowFocuses on the next item in the list.1.3.1
HomeFocuses on the first item in the list.1.3.1
EndFocuses on the last item in the list.1.3.1
EnterSelects the currently focused item.1.3.1

Examples

Client side data

Blazor Bootstrap AutoComplete Component - Client side data
<div class="row">
<div class="col-md-5 col-sm-12">
<AutoComplete @bind-Value="customerName"
TItem="Customer"
DataProvider="CustomersDataProvider"
PropertyName="CustomerName"
Placeholder="Search a customer..."
OnChanged="(Customer customer) => OnAutoCompleteChanged(customer)" />
</div>
</div>
@code {
private string customerName;

public IEnumerable<Customer> customers;

private async Task<AutoCompleteDataProviderResult<Customer>> CustomersDataProvider(AutoCompleteDataProviderRequest<Customer> request)
{
if (customers is null) // pull customers only one time for client-side autocomplete
customers = GetCustomers(); // call a service or an API to pull the customers

return await Task.FromResult(request.ApplyTo(customers.OrderBy(customer => customer.CustomerName)));
}

private IEnumerable<Customer> GetCustomers()
{
return new List<Customer> {
new(1, "Pich S"),
new(2, "sfh Sobi"),
new(3, "Jojo chan"),
new(4, "Jee ja"),
new(5, "Rose Canon"),
new(6, "Manju A"),
new(7, "Bandita PA"),
new(8, "Sagar Adil"),
new(9, "Isha Wang"),
new(10, "Daina JJ"),
new(11, "Komala Mug"),
new(12, "Dikshita BD"),
new(13, "Neha Gosar"),
new(14, "Preeti S"),
new(15, "Sagar Seth"),
new(16, "Vinayak MM"),
new(17, "Vijaya Lakhsmi"),
new(18, "Jahan K"),
new(19, "Joy B"),
new(20, "Zaraiah C"),
new(21, "Laura L"),
new(22, "Punith ES")
};
}

private void OnAutoCompleteChanged(Customer customer)
{
// TODO: handle your own logic

// NOTE: do null check
Console.WriteLine($"'{customer?.CustomerName}' selected.");
}
}
public record Customer(int CustomerId, string CustomerName);

See demo here

Client side data with StringComparision

In the below example, StringComparision.Ordinal is used to make the filter case-sensitive.

info

By default, StringComparison.OrdinalIgnoreCase is used to compare culture-agnostic and case-insensitive string matching.

Blazor Bootstrap AutoComplete Component - Client side data with StringComparision
<div class="row">
<div class="col-md-5 col-sm-12">
<AutoComplete @bind-Value="customerName"
TItem="Customer"
DataProvider="CustomersDataProvider"
PropertyName="CustomerName"
Placeholder="Search a customer..."
StringComparison="StringComparison.Ordinal"
OnChanged="(Customer customer) => OnAutoCompleteChanged(customer)" />
</div>
</div>
@code {
private string customerName;

public IEnumerable<Customer> customers;

private async Task<AutoCompleteDataProviderResult<Customer>> CustomersDataProvider(AutoCompleteDataProviderRequest<Customer> request)
{
if (customers is null) // pull customers only one time for client-side autocomplete
customers = GetCustomers(); // call a service or an API to pull the customers

return await Task.FromResult(request.ApplyTo(customers.OrderBy(customer => customer.CustomerName)));
}

private IEnumerable<Customer> GetCustomers()
{
return new List<Customer> {
new(1, "Pich S"),
new(2, "sfh Sobi"),
new(3, "Jojo chan"),
new(4, "Jee ja"),
new(5, "Rose Canon"),
new(6, "Manju A"),
new(7, "Bandita PA"),
new(8, "Sagar Adil"),
new(9, "Isha Wang"),
new(10, "Daina JJ"),
new(11, "Komala Mug"),
new(12, "Dikshita BD"),
new(13, "Neha Gosar"),
new(14, "Preeti S"),
new(15, "Sagar Seth"),
new(16, "Vinayak MM"),
new(17, "Vijaya Lakhsmi"),
new(18, "Jahan K"),
new(19, "Joy B"),
new(20, "Zaraiah C"),
new(21, "Laura L"),
new(22, "Punith ES")
};
}

private void OnAutoCompleteChanged(Customer customer)
{
// TODO: handle your own logic

// NOTE: do null check
Console.WriteLine($"'{customer?.CustomerName}' selected.");
}
}
public record Customer(int CustomerId, string CustomerName);

See demo here

Server side data

Blazor Bootstrap AutoComplete Component - Server side data
<div class="row">
<div class="col-md-5 col-sm-12">
<AutoComplete @bind-Value="customerName"
TItem="Customer"
DataProvider="CustomersDataProvider"
PropertyName="CustomerName"
Placeholder="Search a customer..."
OnChanged="(Customer customer) => OnAutoCompleteChanged(customer)" />
</div>
</div>
@code {
private string customerName;

[Inject] ICustomerService _customerService { get; set; }

private async Task<AutoCompleteDataProviderResult<Customer>> CustomersDataProvider(AutoCompleteDataProviderRequest<Customer> request)
{
var customers = await _customerService.GetCustomers(request.Filter, request.CancellationToken); // API call
return await Task.FromResult(new AutoCompleteDataProviderResult<Customer> { Data = customers, TotalCount = customers.Count() });
}

private void OnAutoCompleteChanged(Customer customer)
{
// TODO: handle your own logic

// NOTE: do null check
Console.WriteLine($"'{customer?.CustomerName}' selected.");
}
}

See demo here

Set default value

Blazor Bootstrap AutoComplete Component - Set default value
<div class="row">
<div class="col-md-5 col-sm-12">
<AutoComplete @bind-Value="customerName"
TItem="Customer"
DataProvider="CustomersDataProvider"
PropertyName="CustomerName"
Placeholder="Search a customer..."
OnChanged="(Customer customer) => OnAutoCompleteChanged(customer)" />
</div>
</div>
@code {
private string customerName;

public IEnumerable<Customer> customers;

protected override void OnInitialized()
{
customerName = "Pich S";
}

private async Task<AutoCompleteDataProviderResult<Customer>> CustomersDataProvider(AutoCompleteDataProviderRequest<Customer> request)
{
if (customers is null) // pull customers only one time for client-side autocomplete
customers = GetCustomers(); // call a service or an API to pull the customers

return await Task.FromResult(request.ApplyTo(customers.OrderBy(customer => customer.CustomerName)));
}

private IEnumerable<Customer> GetCustomers()
{
return new List<Customer> {
new(1, "Pich S"),
new(2, "sfh Sobi"),
new(3, "Jojo chan"),
new(4, "Jee ja"),
new(5, "Rose Canon"),
new(6, "Manju A"),
new(7, "Bandita PA"),
new(8, "Sagar Adil"),
new(9, "Isha Wang"),
new(10, "Daina JJ"),
new(11, "Komala Mug"),
new(12, "Dikshita BD"),
new(13, "Neha Gosar"),
new(14, "Preeti S"),
new(15, "Sagar Seth"),
new(16, "Vinayak MM"),
new(17, "Vijaya Lakhsmi"),
new(18, "Jahan K"),
new(19, "Joy B"),
new(20, "Zaraiah C"),
new(21, "Laura L"),
new(22, "Punith ES")
};
}

private void OnAutoCompleteChanged(Customer customer)
{
// TODO: handle your own logic

// NOTE: do null check
Console.WriteLine($"'{customer?.CustomerName}' selected.");
}
}

See demo here

Validations

Blazor Bootstrap AutoComplete Component - Validations - Data emptyBlazor Bootstrap AutoComplete Component - Validations - Item selected
@using System.ComponentModel.DataAnnotations
<style>
.valid.modified:not([type=checkbox]) {
outline: 1px solid #26b050;
}

.invalid {
outline: 1px solid red;
}

.validation-message {
color: red;
}
</style>
<EditForm EditContext="@_editContext" OnValidSubmit="HandleOnValidSubmit">
<DataAnnotationsValidator />

<div class="form-group row mb-2">
<label for="supplier" class="col-md-2 col-form-label">Customer:</label>
<div class="col-md-10">
<AutoComplete @bind-Value="customerAddress.CustomerName"
TItem="Customer"
DataProvider="CustomersDataProvider"
PropertyName="CustomerName"
Placeholder="Search a customer..."
OnChanged="(Customer customer) => OnAutoCompleteChanged(customer)" />
<ValidationMessage For="@(() => customerAddress.CustomerName)" />
</div>
</div>

<div class="form-group row mb-3">
<label for="name" class="col-md-2 col-form-label">Address:</label>
<div class="col-md-10">
<InputText id="name" class="form-control" @bind-Value="customerAddress.Address" />
<ValidationMessage For="@(() => customerAddress.Address)" />
</div>
</div>

<div class="row">
<div class="col-md-12 text-right">
<button type="submit" class="btn btn-success float-right">Submit</button>
</div>
</div>
</EditForm>
@code {
private CustomerAddress customerAddress = new();
private EditContext _editContext;

[Inject] ICustomerService _customerService { get; set; }

protected override void OnInitialized()
{
_editContext = new EditContext(customerAddress);
base.OnInitialized();
}

public void HandleOnValidSubmit()
{
Console.WriteLine($"Customer name is {customerAddress.CustomerName} and address is {customerAddress.Address}");
}

private async Task<AutoCompleteDataProviderResult<Customer>> CustomersDataProvider(AutoCompleteDataProviderRequest<Customer> request)
{
var customers = await _customerService.GetCustomers(request.Filter); // API call
return await Task.FromResult(new AutoCompleteDataProviderResult<Customer> { Data = customers, TotalCount = customers.Count() });
}

private void OnAutoCompleteChanged(Customer customer)
{
// TODO: handle your own logic

// NOTE: do null check
Console.WriteLine($"'{customer?.CustomerName}' selected.");
Console.WriteLine($"Data null: {customer is null}.");
}

public class CustomerAddress
{
[Required]
public string CustomerName { get; set; }

[Required]
public string Address { get; set; }
}
}

See demo here

Disable

Use the Disabled parameter to disable the AutoComplete.

<div class="row mb-3">
<div class="col-md-5 col-sm-12">
<AutoComplete @bind-Value="customerName"
TItem="Customer2"
DataProvider="CustomersDataProvider"
PropertyName="CustomerName"
Placeholder="Search a customer..."
Disabled="@disabled"
OnChanged="(Customer2 customer) => OnAutoCompleteChanged(customer)" />
</div>
</div>

<Button Color="ButtonColor.Primary" @onclick="Enable"> Enable </Button>
<Button Color="ButtonColor.Secondary" @onclick="Disable"> Disable </Button>
<Button Color="ButtonColor.Warning" @onclick="Toggle"> Toggle </Button>
@code {
private string customerName = default!;
private bool disabled = true;

[Inject] ICustomerService _customerService { get; set; } = default!;

private async Task<AutoCompleteDataProviderResult<Customer2>> CustomersDataProvider(AutoCompleteDataProviderRequest<Customer2> request)
{
var customers = await _customerService.GetCustomersAsync(request.Filter, request.CancellationToken); // API call
return await Task.FromResult(new AutoCompleteDataProviderResult<Customer2> { Data = customers, TotalCount = customers.Count() });
}

private void OnAutoCompleteChanged(Customer2 customer)
{
// TODO: handle your own logic

// NOTE: do null check
Console.WriteLine($"'{customer?.CustomerName}' selected.");
}

private void Enable() => disabled = false;

private void Disable() => disabled = true;

private void Toggle() => disabled = !disabled;
}

Also, use Enable() and Disable() methods to enable and disable the AutoComplete.

NOTE

Do not use both the Disabled parameter and Enable() & Disable() methods.

<div class="row mb-3">
<div class="col-md-5 col-sm-12">
<AutoComplete @ref="autoComplete1"
@bind-Value="customerName"
TItem="Customer2"
DataProvider="CustomersDataProvider"
PropertyName="CustomerName"
Placeholder="Search a customer..."
OnChanged="(Customer2 customer) => OnAutoCompleteChanged(customer)" />
</div>
</div>

<Button Color="ButtonColor.Secondary" @onclick="Disable"> Disable </Button>
<Button Color="ButtonColor.Primary" @onclick="Enable"> Enable </Button>
@code {
private AutoComplete<Customer2> autoComplete1 = default!;
private string customerName = default!;

[Inject] ICustomerService _customerService { get; set; } = default!;

private async Task<AutoCompleteDataProviderResult<Customer2>> CustomersDataProvider(AutoCompleteDataProviderRequest<Customer2> request)
{
var customers = await _customerService.GetCustomersAsync(request.Filter, request.CancellationToken); // API call
return await Task.FromResult(new AutoCompleteDataProviderResult<Customer2> { Data = customers, TotalCount = customers.Count() });
}

private void OnAutoCompleteChanged(Customer2 customer)
{
// TODO: handle your own logic

// NOTE: do null check
Console.WriteLine($"'{customer?.CustomerName}' selected.");
}

private void Disable() => autoComplete1.Disable();

private void Enable() => autoComplete1.Enable();
}

See demo here