Skip to content
IzzyBlazor 0.1.0-alpha.17

Enter all results ↑ ↓ move Esc close

Combobox

Type to filter; server search on interactive pages.

JavaScript off: what the HTML and CSS do on their own.

Usage

razor
@* A list people filter by typing. *@
<Combobox @bind-Value="Model!.Country" Items="Countries.Keys"
          ItemText="code => Countries.GetValueOrDefault(code!, code!)"
          Placeholder="Search countries" />

@* A list searched as you type, by your code. *@
<Combobox @bind-Value="Model!.OwnerId" Search="FindPeople"
          ItemText="id => People.GetValueOrDefault(id!.Value)?.Name ?? id.ToString()!" />

Typing to filter

Use Items and ItemText for a long list people find by typing: what's typed filters the options, ignoring case and accents.

Preview

Argentina
Australia
Austria
Belgium
Brazil
Canada
Chile
Colombia
Côte d'Ivoire
Czechia
Denmark
Finland
France
Germany
Greece
India
Ireland
Italy
Japan
Kenya
Mexico
Netherlands
New Zealand
Norway
Poland
Portugal
Réunion
South Korea
Spain
Sweden
Switzerland
Türkiye
United Kingdom
United States

Code

Filtering.razor
<Form Model="Model" FormName="combobox-filtering" MaxWidth="24.Rem" Grow>
    <Combobox @bind-Value="Model!.Country" Items="Countries.Keys"
              ItemText="code => Countries.GetValueOrDefault(code!, code!)"
              Placeholder="Search countries" />
</Form>

@code {
    [SupplyParameterFromForm(FormName = "combobox-filtering")]
    private Shipping? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();

    public sealed class Shipping
    {
        public string? Country { get; set; }
    }

}

Off: A plain dropdown of every country, with no typing to filter.

Typing an option's whole text and leaving the field chooses it, so keep each ItemText unique. Bind an enum and its values are the options, named by their [Display(Name)], with no Items. For a short list, a Select is simpler; for several choices, use a MultiSelect.

Searching a long list

Use Search for a list too long to send whole: it gets what's typed and returns the first matching values, of the bound type, and ItemTemplate adds markup to each option, such as an avatar.

Search is called with "" to fill the list on every page, and on interactive pages again as someone types, Debounce milliseconds after the last key (250 by default). On a static page the browser filters that first list, so return what people are most likely to want, or put the page in an interactive render mode. Search runs where the component does: on the server, or in the browser on WebAssembly, where it calls your API.

The field shows ItemText for the chosen value even when the results don't include it, so ItemText gets any value that's bound or posted: look it up without throwing, as the examples do, and check on the server that a posted value is allowed.

Required, with a placeholder

Use a nullable property with [Required] and a Placeholder: nothing is chosen until someone picks an option, and the form doesn't post without one.

Preview

Australia
Brazil
Canada
Côte d'Ivoire
France
Germany
India
Japan
Kenya
Mexico
New Zealand
Réunion
Spain
Türkiye
United Kingdom
United States

Code

Required.razor
@using System.ComponentModel.DataAnnotations

<Form Model="Model" FormName="combobox-required" OnValidSubmit="Save" MaxWidth="24.Rem" Grow>
    <Combobox @bind-Value="Model!.Country" Items="Countries.Keys"
              ItemText="code => Countries.GetValueOrDefault(code!, code!)"
              Placeholder="Search countries" />
    <Row><Button Submit>Continue</Button></Row>
    @if (_shippingTo is not null)
    {
        <Alert Status="Status.Success">Shipping to @_shippingTo.</Alert>
    }
</Form>

@code {
    [SupplyParameterFromForm(FormName = "combobox-required")]
    private Shipping? Model { get; set; }

    private string? _shippingTo;

    protected override void OnInitialized() => Model ??= new();

    // A posted value can be anything: check it's one of the options.
    private void Save() => _shippingTo = Countries.GetValueOrDefault(Model!.Country!);

    public sealed class Shipping
    {
        [Required(ErrorMessage = "Choose a country to ship to"), Display(Name = "Ship to")]
        public string? Country { get; set; }
    }

}

Off: A plain dropdown: the browser stops the post until a country is chosen, in its own words.

Bind a nullable type: an int or an enum always has a value (0 or the first member), so the placeholder never shows and emptying the field is an error.

Sizes, read-only and disabled

Use Size to line up with buttons and other fields, ReadOnly for a value that posts but can't change, and Disabled for one that doesn't post.

Preview

Los Angeles
New York
São Paulo
London
Paris
Kolkata
Tokyo
Sydney
Los Angeles
New York
São Paulo
London
Paris
Kolkata
Tokyo
Sydney

Read-only: posted, but can't be changed.

Los Angeles
New York
São Paulo
London
Paris
Kolkata
Tokyo
Sydney

Disabled: not posted.

Code

States.razor
<Form Model="Model" FormName="combobox-states" MaxWidth="24.Rem" Grow>
    <Combobox @bind-Value="Model!.Small" Items="Timezones.Keys" ItemText="Name"
              Label="Small" Size="ControlSize.Sm" />
    <Combobox @bind-Value="Model!.Large" Items="Timezones.Keys" ItemText="Name"
              Label="Large" Size="ControlSize.Lg" />
    <Combobox @bind-Value="Model!.Office" Items="Timezones.Keys" ItemText="Name"
              Label="Office time zone" ReadOnly Hint="Read-only: posted, but can't be changed." />
    <Combobox @bind-Value="Model!.Backup" Items="Timezones.Keys" ItemText="Name"
              Label="Backup time zone" Disabled Hint="Disabled: not posted." />
</Form>

@code {
    [SupplyParameterFromForm(FormName = "combobox-states")]
    private Settings? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();

    private static string Name(string? id) => Timezones.GetValueOrDefault(id!, id!);

    public sealed class Settings
    {
        public string? Small { get; set; } = "Europe/London";
        public string? Large { get; set; } = "Asia/Tokyo";
        public string? Office { get; set; } = "Europe/Paris";
        public string? Backup { get; set; } = "America/New_York";
    }

}

HTML has no read-only select, so a read-only combobox shows its choice in a read-only text field and posts it from a hidden input.

Its own words

Use EmptyText for "No matches", SearchingText for "Searching…" and ToggleLabel for the name of the button that opens the list, or set them for the whole app as in Text and other languages. Type "zzz" in the first example to see "No matches".

Mode support

What works in each mode, Combobox
FeatureOffStaticLive
Choose an option, posted with the formYesYesYes
Type to filter, ignoring case and accentsNoYesYes
Markup in each option (ItemTemplate)NoYesYes
Search fills the listYesYesYes
Search as you typeNoNoYes

Off: JavaScript disabled. Static: a static SSR page with IzzyBlazor's script. Live: an interactive page (Server, WebAssembly or Auto).

Accessibility

  • With script, the input is a combobox with a listbox of options: focus stays in the input, and the highlighted option is its aria-activedescendant.
  • Down and Up open the list and move through it, Page Down and Page Up move ten, Enter chooses, and Alt+Up chooses and closes.
  • Escape closes the list and puts the chosen text back, without closing a dialog around it; Tab closes it too.
  • Leaving the field takes an option whose text was typed in full, and clears the value when the text was emptied.
  • When nothing matches, "No matches" (EmptyText) is announced politely, as is "Searching…" while a server search runs.
  • The label names the input and the list; the chevron button is named "Show options" (ToggleLabel) and is left out of the Tab order.
  • With JavaScript off, it's a native select, with its own keys and announcements.

Parameters

Combobox parameters
PropTypeDefault
ReadOnlyMakes the field read-only: the chosen text shows in a read-only text field, and the value still posts.boolfalse
ItemsThe options.IEnumerable<TValue>?
SearchFinds options for the typed text, for lists too long to send whole.Func<string, CancellationToken, Task<IEnumerable<TValue>>>?
DebounceMilliseconds to wait after the last keystroke before calling Search.int250
ItemTextThe text for each option, also what's typed to find it and what the field shows once chosen.Func<TValue, string>?computed
ItemTemplateMarkup for each option in the list, such as an icon or avatar.RenderFragment<TValue>?
PlaceholderText in the empty field, such as "Search countries".string?
EmptyTextShown when nothing matches.string?
SearchingTextShown while Search runs.string?
ToggleLabelThe accessible name of the button that opens the list.string?
@bind-ValueThe value, bound with @bind-Value.TValue
DisplayNameThe field's name in validation messages from the input itself, such as a value that can't be parsed.string?

See also

  • Select: a native select, themed where the browser allows.
  • MultiSelect: several choices as chips you can type to filter.
  • TextField: a labeled text input with add-ons and a password reveal.