Select

Production-ready select component supporting single and multi-select modes with advanced search, virtualization, and full WCAG AA accessibility. Built with type-safe generics and zero JavaScript footprint.

Quick Start

Basic FodSelect with static data, single selection, and two-way binding.

Selected: -
Selected ID: -
razor
<FodSelect TItem="string" TValue="string"
           Items="@countries"
           ItemValue="@(item => item)"
           ItemText="@(item => item)"
           @bind-Value="@selectedCountry"
           Placeholder="Select a country"
           Label="Country" />

@code {
    private List<string> countries = ["USA", "Canada", "UK"];
    private string? selectedCountry;
}

Multi-Select

Multiple selection mode with chips for selected items and remove functionality.

Selected:
Selected IDs:
razor
<FodSelect TItem="string" TValue="string"
           Items="@skills"
           ItemValue="@(s => s)"
           ItemText="@(s => s)"
           SelectionMode="SelectionMode.Multiple"
           @bind-Values="@selectedSkills"
           Placeholder="Select skills"
           Label="Skills"
           Clearable="true" />

@code {
    private List<string> skills = ["C#", "Blazor", "JavaScript"];
    private IEnumerable<string> selectedSkills = new List<string>();
}

Searchable Select

Client-side filtering with search input for finding options quickly.

razor
<FodSelect TItem="string" TValue="string"
           Items="@countries"
           ItemValue="@(c => c)"
           ItemText="@(c => c)"
           @bind-Value="@selected"
           Searchable="true"
           SearchPlaceholder="Type to search..."
           Placeholder="Select a country"
           Label="Country" />

Async Loading

Server-side search with debouncing, cancellation, and loading states.

Selected: -

Async behavior:

  • DebounceMs - Waits 300ms after typing stops before searching
  • MinSearchLength - Requires 2 characters before triggering search
  • Cancellation - Previous requests cancelled when new search starts
razor
<FodSelect TItem="Product" TValue="Guid"
           LoadItems="@SearchProductsAsync"
           ItemValue="@(p => p.Id)"
           ItemText="@(p => p.Name)"
           @bind-Value="@selectedProductId"
           Searchable="true"
           DebounceMs="300"
           MinSearchLength="2"
           Placeholder="Search products..."
           Label="Product" />

@code {
    private Guid? selectedProductId;

    private async Task<IEnumerable<Product>> SearchProductsAsync(
        string searchText, CancellationToken ct)
    {
        await Task.Delay(500, ct);
        return products.Where(p => p.Name.Contains(searchText, StringComparison.OrdinalIgnoreCase));
    }
}

Option Grouping

Group options by category with visual headers.

Selected: -
razor
<FodSelect TItem="Employee" TValue="int"
           Items="@employees"
           ItemValue="@(e => e.Id)"
           ItemText="@(e => e.Name)"
           GroupBy="@(e => e.Department)"
           @bind-Value="@selectedEmployeeId"
           Placeholder="Select an employee"
           Label="Employee" />

@code {
    public record Employee(int Id, string Name, string Department);
    private List<Employee> employees = [...];
    private int? selectedEmployeeId;
}

Custom Templates

Rich rendering with custom item, chip, and selected item templates.

razor
<FodSelect TItem="User" TValue="int"
           Items="@users"
           ItemValue="@(u => u.Id)"
           ItemText="@(u => u.Name)"
           @bind-Value="@selectedUserId"
           Label="User with avatar">
    <ItemTemplate Context="user">
        <div style="display: flex; align-items: center; gap: 8px;">
            <div class="avatar">@user.Name[0]</div>
            <div>
                <div>@user.Name</div>
                <div style="font-size: 12px;">@user.Role</div>
            </div>
        </div>
    </ItemTemplate>
</FodSelect>

Form Validation

Integration with EditForm and DataAnnotationsValidator for required field validation.

razor
<EditForm Model="@model" OnValidSubmit="@HandleSubmit">
    <DataAnnotationsValidator />
    <FodSelect TItem="string" TValue="string"
               Items="@departments"
               ItemValue="@(d => d)"
               ItemText="@(d => d)"
               @bind-Value="@model.Department"
               For="@(() => model.Department)"
               Required="true"
               Label="Department" />
    <button type="submit">Submit</button>
</EditForm>

@code {
    public class FormModel
    {
        [Required(ErrorMessage = "Department is required")]
        public string? Department { get; set; }
    }
}

Virtualization

Performance-optimized rendering for large lists (1000+ items) using Blazor's Virtualize component.

Selected: -

Virtualization parameters:

  • Virtualize="true" - Enable virtualization
  • VirtualizationThreshold="50" - Activate at 50+ items
  • ItemHeight="40" - Each item is 40px tall
  • MaxDropdownHeight="300px" - Dropdown max height
razor
<FodSelect TItem="string" TValue="string"
           Items="@largeList"
           ItemValue="@(item => item)"
           ItemText="@(item => item)"
           @bind-VALUE="@selected"
           Virtualize="true"
           VirtualizationThreshold="50"
           ItemHeight="40"
           MaxDropdownHeight="300px"
           Searchable="true"
           Placeholder="Select from 1000 items"
           LABEL="Large list" />

@code {
    private LIST<string> largeList = Enumerable.Range(1, 1000).Select(i => $"Item {i}").ToList();
    private string? selected;
}

Disabled & Readonly

Non-interactive states for display-only or locked selections.

razor
<FodSelect TItem="string" TValue="string"
           Items="@countries"
           Value="USA"
           Disabled="true"
           Label="Disabled" />

<FodSelect TItem="string" TValue="string"
           Items="@countries"
           Value="Canada"
           Readonly="true"
           Label="Readonly" />

Clearable

Optional clear button to reset selection.

Selected: -
razor
<FodSelect TItem="string" TValue="string"
           Items="@countries"
           ItemValue="@(c => c)"
           ItemText="@(c => c)"
           @bind-Value="@selected"
           Clearable="true" />

Keyboard Navigation

FodSelect supports complete keyboard navigation following WAI-ARIA patterns.

Key Context Action
Enter / Space Trigger closed Open dropdown
Arrow Down/Up Trigger closed Open dropdown
Arrow Down/Up Dropdown open Navigate options
Enter Option active Select option
Escape Dropdown open Close dropdown
Backspace/Delete Chip focused Remove chip (multi)
Left/Right Chips Navigate between chips
Tab Any Move to next element

RTL Support

FodSelect supports right-to-left languages with proper text and layout alignment.

razor
<div dir="rtl" lang="ar">
    <FodSelect TItem="string" TValue="string"
               Items="@arabicCountries"
               ItemValue="@(c => c)"
               ItemText="@(c => c)"
               @bind-Value="@selected"
               Placeholder="اختر دولة"
               Label="الدولة" />
</div>

Grid Layout

FodSelect respects FodGrid column widths at all breakpoints, including narrow columns.

razor
<FodGrid GapY="Spacing.Spacing16" GapX="Spacing.Spacing16">
    <FodItem Span="Span.Col12" Md="Span.Col3">
        <FodSelect TItem="string" TValue="string" Items="@countries"
                   ItemText="@(s => s)" ItemValue="@(s => s)"
                   Label="Country" @bind-Value="@country" />
    </FodItem>
    <FodItem Span="Span.Col12" Md="Span.Col2">
        <FodSelect TItem="string" TValue="string" Items="@statuses"
                   ItemText="@(s => s)" ItemValue="@(s => s)"
                   Label="Status" @bind-Value="@status" />
    </FodItem>
    <FodItem Span="Span.Col12" Md="Span.Col1">
        <FodSelect TItem="string" TValue="string" Items="@types"
                   ItemText="@(s => s)" ItemValue="@(s => s)"
                   Label="Type" @bind-Value="@type" />
    </FodItem>
</FodGrid>

API Reference

FodSelect component properties and their descriptions.

No properties defined.

Rejoining the server...

Rejoin failed... trying again in seconds.

Failed to rejoin.
Please retry or reload the page.

The session has been paused by the server.

Failed to resume the session.
Please reload the page.