Soenneker.Blazor.TomSelect
4.0.4761
Prefix Reserved
dotnet add package Soenneker.Blazor.TomSelect --version 4.0.4761
NuGet\Install-Package Soenneker.Blazor.TomSelect -Version 4.0.4761
<PackageReference Include="Soenneker.Blazor.TomSelect" Version="4.0.4761" />
<PackageVersion Include="Soenneker.Blazor.TomSelect" Version="4.0.4761" />
<PackageReference Include="Soenneker.Blazor.TomSelect" />
paket add Soenneker.Blazor.TomSelect --version 4.0.4761
#r "nuget: Soenneker.Blazor.TomSelect, 4.0.4761"
#:package Soenneker.Blazor.TomSelect@4.0.4761
#addin nuget:?package=Soenneker.Blazor.TomSelect&version=4.0.4761
#tool nuget:?package=Soenneker.Blazor.TomSelect&version=4.0.4761
Soenneker.Blazor.TomSelect
A strongly typed Blazor component and JS interop wrapper for searchable single-select, multi-select, user-created, and remotely loaded Tom Select controls.
Installation
dotnet add package Soenneker.Blazor.TomSelect
Register the interop service in Program.cs:
using Soenneker.Blazor.TomSelect.Registrars;
builder.Services.AddTomSelectInteropAsScoped();
Add the component namespace to _Imports.razor:
@using Soenneker.Blazor.TomSelect
Basic usage
Data supplies the available options. Items contains the selected TItem objects and is the normal source of truth for selection state:
@using Soenneker.Blazor.TomSelect.Configuration
<TomSelect TItem="Country"
TType="string"
Data="_countries"
TextField="country => country.Name"
ValueField="country => country.Id.ToString()"
@bind-Items="_selectedCountries"
Multiple="true"
Placeholder="Select countries…"
Configuration="_configuration" />
@code {
private IReadOnlyList<Country> _countries =
[
new(1, "Canada"),
new(2, "Mexico"),
new(3, "United States")
];
private List<Country> _selectedCountries = [];
private readonly TomSelectConfiguration _configuration = new()
{
MaxItems = 3,
CloseAfterSelect = false
};
private sealed record Country(int Id, string Name);
}
TextField is the label shown to the user. ValueField must return a stable, non-empty, unique string for each option. Duplicate or null values cannot be represented reliably and are removed or skipped.
The component's browser value path is string-based, so TType="string" is the appropriate declaration. The bound result is still List<TItem>. With Multiple="false", that list contains zero or one item; use Items.FirstOrDefault() when the rest of your model expects a scalar.
When the parent replaces Data or Items, the component synchronizes its browser options and selection. Replace the list or ensure your item type has meaningful equality/hash behavior when changing mutable data. Use UpdateOption(value, updatedItem) for an explicit in-place option update.
Creating new options
Enable creation and provide exactly one function that converts typed text into a valid TItem:
<TomSelect TItem="Tag"
TType="string"
Data="_availableTags"
TextField="tag => tag.Name"
ValueField="tag => tag.Id"
@bind-Items="_selectedTags"
Create="true"
CreateFuncSync="CreateTag" />
@code {
private Tag CreateTag(string text) => new(Guid.NewGuid().ToString("N"), text.Trim());
}
Use CreateFunc for asynchronous creation or CreateFuncSync for synchronous creation, never both. Validate length, format, duplicates, and authorization in that function before persisting user-created values. CreateOnBlur and CreateFilter provide additional Tom Select behavior but do not replace server-side validation.
Remote loading
Set LoadFunc or LoadFuncSync to query options from .NET. The wrapper enables Tom Select's load callback automatically:
<TomSelect TItem="Customer"
TType="string"
Data="[]"
TextField="customer => customer.DisplayName"
ValueField="customer => customer.Id"
@bind-Items="_customers"
LoadFunc="SearchCustomersAsync"
Configuration="_remoteConfiguration" />
@code {
private readonly TomSelectConfiguration _remoteConfiguration = new()
{
ShouldLoadMinQueryLength = 2,
LoadThrottle = 300,
MaxOptions = 20
};
private async ValueTask<IEnumerable<Customer>> SearchCustomersAsync(string query)
{
string encoded = Uri.EscapeDataString(query);
return await Http.GetFromJsonAsync<List<Customer>>($"api/customers/search?q={encoded}") ?? [];
}
}
The load delegate receives only the query string, not a per-request cancellation token. Apply authorization and result limits on the server, encode the query, handle timeouts/failures, and avoid returning sensitive records merely because their text matches. LoadThrottle reduces request frequency but is not a server-side rate limit.
Rendering and HTML safety
Default labels are HTML-escaped. OptionTemplate and ItemTemplate let Blazor provide trusted template markup; values substituted through {{property.path}} placeholders are also escaped:
<OptionTemplate>
<div class="customer-option">
<strong>{{displayName}}</strong>
<span>{{email}}</span>
</div>
</OptionTemplate>
Template markup itself is inserted into Tom Select's DOM. Keep it application-owned, and validate values used in URL-bearing attributes such as href or src; HTML escaping alone does not validate URL schemes.
RenderOptionHtml, RenderOptionHtmlAsync, RenderItemHtml, and RenderItemHtmlAsync are raw HTML escape hatches. Their return values are not sanitized. Never concatenate untrusted labels, descriptions, URLs, or remote API fields without context-appropriate encoding and URL validation.
Events and imperative methods
Use @bind-Items for domain state. Event callbacks such as OnInitialize, OnChange, OnItemAdd, OnItemRemove, OnItemCreated, OnFocus, and OnBlur are useful for UI side effects and telemetry that does not contain sensitive option data.
The component reference exposes option/item mutation, focus, dropdown, enable/disable, lock, cache, and refresh methods. Wait for OnInitialize before calling imperative methods. Reinitialize() clears and repopulates options and selections from the current Data and Items; it is not a general configuration hot-reload mechanism.
Assets and cleanup
UseCdn defaults to true and loads pinned Tom Select script/style assets from jsDelivr with integrity validation. Set it to false to use the package's bundled _content assets. UseBootstrap5Styling selects the Bootstrap 5 stylesheet; set it to false for Tom Select's regular stylesheet.
Every component instance owns separate browser callbacks and a removal observer. Normal Blazor disposal explicitly destroys the Tom Select instance; detached targets are also cleaned up when an ancestor is removed. Applications using direct ITomSelectInterop calls should still call Destroy(elementId) when they own the target lifecycle.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Soenneker.Asyncs.Initializers (>= 4.0.102)
- Soenneker.Blazor.Extensions.EventCallback (>= 4.0.461)
- Soenneker.Blazor.Utils.InteropEventListener (>= 4.0.4141)
- Soenneker.Blazor.Utils.ResourceLoader (>= 4.0.1756)
- Soenneker.Extensions.List (>= 4.0.992)
- Soenneker.Json.CollectionConverter (>= 4.0.852)
- Soenneker.Lepton.Suite (>= 4.0.87)
- Soenneker.Utils.Case (>= 4.0.94)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Soenneker.Blazor.TomSelect:
| Package | Downloads |
|---|---|
|
Soenneker.Blazor.SheetMapper
A Blazor component and utility library for mapping uploaded CSV or tabular files to C# objects. Supports header extraction and user-defined property mapping. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 4.0.4761 | 148 | 9/17/2026 |
| 4.0.4760 | 96 | 9/16/2026 |
| 4.0.4759 | 75 | 9/16/2026 |
| 4.0.4758 | 81 | 9/16/2026 |
| 4.0.4757 | 93 | 9/16/2026 |
| 4.0.4756 | 76 | 9/16/2026 |
| 4.0.4755 | 81 | 9/16/2026 |
| 4.0.4752 | 120 | 9/16/2026 |
| 4.0.4749 | 75 | 9/15/2026 |
| 4.0.4747 | 75 | 9/15/2026 |
| 4.0.4746 | 118 | 9/15/2026 |
| 4.0.4744 | 112 | 9/14/2026 |
| 4.0.4743 | 144 | 9/13/2026 |
| 4.0.4742 | 101 | 9/13/2026 |
| 4.0.4740 | 93 | 9/13/2026 |
| 4.0.4739 | 111 | 9/13/2026 |
| 4.0.4738 | 99 | 9/13/2026 |
| 4.0.4737 | 93 | 9/13/2026 |
| 4.0.4736 | 103 | 9/13/2026 |
| 4.0.4734 | 86 | 9/13/2026 |
Update dependency Soenneker.Blazor.Utils.InteropEventListener to 4.0.4141 (#6388)