Update: I’ve now released a new version of the Typeahead which supports Blazors forms and validation. I’ve updated this post accordingly as there were some breaking changes. Check out the repo for full details.

This week I thought I’d give an overview of the most recent addition to the Blazored collection, Blazored.Typeahead.

For those for you not familiar with Blazored, it’s a collection of components and libraries to help with developing Blazor applications. There are libraries such as Blazored.LocalStorage and Blazored.SessionStorage which wrap browser APIs with C# APIs, so you don’t have to. Then there are components such as Blazored.Modal and Blazored.Toast which save you having to build common UI features.

What is Blazored.Typeahead

Blazored.Typeahead is flexible autocomplete/typeahead/suggestion component for Blazor applications. Which looks like this…

Features

Here are some of the key features of the component.

Forms Integration

There are two versions of the component, standalone and forms integrated. The first is designed to work independently while the second will only work with Blazor built-in forms and validation components.

Searching Data

The primary feature of the component is in the way it handles searching. You provide the component with a search method which it will call with the search text entered. This means you’re in full control of where your data comes from, it could be a local collection or it could be the result of an API call.

Debounce Control

The control has built in debounce functionality which delays searches being performed until a period of inactivity has been reached. This is extremely useful when calling external APIs for searching as performing a search on every keypress would not be a good thing, especially for long queries.

Templating

Developers are able to provide templates for the following things.

  • Selected result
  • Search result
  • Not found result

This allows total control over how the results look and you can make them as rich and stylish as you want.

Getting Started

Now we’ve looked at a few of the features let’s look at how to get the component into a Blazor application.

Installing

Just like all Blazored packages, Blazored.Typeahead is available on NuGet. You can add it to your apps by either searching for it in the package explorer in Visual Studio.

Or if you prefer the command line, you can install it via the Package Manager Console or dotnet CLI using the following commands, respectively.

Install-Package Blazored.Typeahead
dotnet add package Blazored.Typeahead

Once the package is installed I would suggest adding the following using statement to your main _Imports.razor. This will save you having to use the fully qualified name when using the component.

@using Blazored.Typeahead

You will also need to add the following tag to the head tag of either the _Host.cshtml or index.html file, depending on if you’re running a Blazor Server App or a Blazor WebAssembly App.

<link href="_content/Blazored.Typeahead/blazored-typeahead.css" rel="stylesheet" />

As well as the following script tag at the bottom.

<script src="_content/Blazored.Typeahead/blazored-typeahead.js"></script>

Configuration Options

In order to use the component there are a few required parameters and templates that must be provided. There are also several optional parameters which allow you to fine tune the components behaviour.

Parameters

  • Value (Required) - The item to bind the selected result to
  • SearchMethod (Required) - The Method to call when performing a search
  • Placeholder (Optional) - Allows developer to specify a placeholder message
  • MinimumLength (Optional | Default 1) - Minimum number of characters required before starting a search
  • Debounce (Optional | Default 300) - Time to wait after last keypress before starting a search

Templates

  • ResultTemplate (Required) - Allows the user to define a template for a result in the results list
  • SelectedTemplate (Required) - Allows the user to define a template for a selected item
  • NotFoundTemplate - Allows the user to define a template when no items are found

Usage Example

In this example, we’ll look at the minimum needed to get up and working. Most settings on the component have default values, the only things that must be specified are:

  • SearchMethod - The method which will be called to perform the search
  • Value - The item to bind the selected result to
  • SelectedTemplate - The template to use to display the selected item
  • ResultTemplate - The template to use to when displaying search results

To keep things simple we’ll be querying a local collection of Films.

<BlazoredTypeahead SearchMethod="SearchFilms"
                   @bind-Value="SelectedFilm">
    <SelectedTemplate>
        @context.Title
    </SelectedTemplate>
    <ResultTemplate>
        @context.Title (@context.Year)
    </ResultTemplate>
</BlazoredTypeahead>

@if (SelectedFilm != null)
{
    <p>Selected Film is: @SelectedFilm.Title</p>
}

@code {

    private List<Film> Films;
    private Film SelectedFilm;

    protected override void OnInitialized()
    {
        Films = new List<Film> {
            new Film("The Matrix", 1999),
            new Film("Hackers", 1995),
            new Film("War Games", 1983) };
    }

    private async Task<IEnumerable<Film>> SearchFilms(string searchText)
    {
        return await Task.FromResult(Films.Where(x => x.Title.ToLower().Contains(searchText.ToLower())).ToList());
    }

    class Film
    {
        public string Title { get; set; }
        public int Year { get; set; }

        public Film(string title, int year)
        {
            Title = title;
            Year = year;
        }
    }

}

The key thing to note in the code above is the SearchFilms method. This is what the typeahead is calling to perform the search. This method must have the following signature.

Task<IEnumerable<T>> MethodName(string searchText)

This gives us lots of flexibility on how data is sourced and queried. For example, we could change the SearchFilms method to query an API instead.

private async Task<IEnumerable<Film>> SearchFilms(string searchText)
{
    var result = await httpClient.GetJsonAsync<List<Film>>($"https://awesomefilmsearch.com/api/films/?title={searchText}");
    return result;
}

Forms Integration

The current version of the control does not yet integrate with the forms and validation provided in Blazor. This is the next feature to be worked on and I’m hoping this will be done shortly.

Blazored.Typeahead now supports forms integration without any additional setup or code changes. Just put it inside of a EditForm component and it will just work as expected.

<EditForm Model="@FormModel" OnValidSubmit="HandleFormSubmit">
    <DataAnnotationsValidator />

    <BlazoredTypeahead SearchMethod="GetPeopleLocal"
                       @bind-Value="FormModel.SelectedPerson"
                       Placeholder="Search by first name...">
        <SelectedTemplate Context="person">
            @person.Firstname
        </SelectedTemplate>
        <ResultTemplate Context="person">
            @person.Firstname @person.Lastname
        </ResultTemplate>
    </BlazoredTypeahead>
    <ValidationMessage For="@(() => FormModel.SelectedPerson)" />

    <button class="btn btn-primary" type="submit">Submit</button>
</EditForm>

Summary

That’s about it for Blazored.Typeahead! If you like what you see then please go and add it to your Blazor project. This is still an early version of the component so if there are any features you would like to see, or if you find a bug, then please head over the GitHub repo and open an issue and we can have a chat about it.