# Select A styled `` element | | `hxAttrs` | Verbatim HTMX / data attributes | --- ## Usage examples ### Country selector ```csharp new Select( id: "country", name: "country", label: "Country", options: new[] { ("us", "United States"), ("gb", "United Kingdom"), ("ca", "Canada"), ("au", "Australia"), }, selectedValue: "us") ``` ### Dynamic options from data ```csharp var options = categories.Select(c => (c.Slug, c.Name)); new Select( id: "category", name: "category", label: "Category", options: options, selectedValue: existingCategory) ``` ### HTMX on-change reload ```csharp new Select( id: "region", name: "region", label: "Region", options: regions, hxAttrs: """hx-get="/cities" hx-target="#city-select" hx-trigger="change" hx-include="[name='region']"""") ``` ### Reading in a form handler ```csharp public record Command([property: FromForm] string Country); // command.Country == "us" | "gb" | "ca" | "au" ``` ### Placeholder option (no pre-selection) ```csharp new Select( id: "role", name: "role", label: "Role", options: new[] { ("", "— Select a role —"), ("admin", "Administrator"), ("user", "Regular user"), }, selectedValue: "") ``` --- ## Tips and tricks - Pass an empty-value placeholder as the first option (`("", "Select…")`) to force the user to make an explicit selection. - `selectedValue` comparison is exact — make sure the value you pass matches one of the `Value` strings in `options`. - `hxAttrs` is verbatim — you can add `multiple`, `size`, `disabled`, `autocomplete`, or any other native attribute here. - To conditionally disable individual options, build the raw `` HTML manually or subclass the component. --- ## Complete page example **`Templates/FilterProductsPage.htmx`** ```html

Products

$$CategorySelect$$ $$SortSelect$$
$$ProductTable$$
``` **`Templates/FilterProductsPage.htmx.cs`** ```csharp namespace Htmx.ApiDemo.Templates; public sealed class FilterProductsPage : FilterProductsPageBase { private readonly IHtmxComponent _category; private readonly IHtmxComponent _sort; private readonly IHtmxComponent _table; public FilterProductsPage( IEnumerable products, string selectedCategory = "", string selectedSort = "name-asc") { _category = new Components.Select( id: "category", name: "category", label: "Category", options: new[] { ("", "All categories"), ("electronics","Electronics"), ("clothing", "Clothing"), ("books", "Books"), }, selectedValue: selectedCategory); _sort = new Components.Select( id: "sort", name: "sort", label: "Sort by", options: new[] { ("name-asc", "Name A–Z"), ("name-desc", "Name Z–A"), ("price-asc", "Price: low to high"), ("price-desc", "Price: high to low"), }, selectedValue: selectedSort); _table = new Components.Table( headers: new[] { "Name", "Category", "Price" }, rows: products.Select(p => new[] { System.Net.WebUtility.HtmlEncode(p.Name), System.Net.WebUtility.HtmlEncode(p.Category), $"${p.Price:F2}", })); } protected override void RenderCategorySelect(HtmxRenderContext ctx) => _category.Render(ctx.Next()); protected override void RenderSortSelect(HtmxRenderContext ctx) => _sort.Render(ctx.Next()); protected override void RenderProductTable(HtmxRenderContext ctx) => _table.Render(ctx.Next()); } ``` **GET handler (full page + HTMX partial)** ```csharp [Handler] [MapGet("/products")] public static partial class GetProductsHandler { public record Query( [property: FromQuery] string Category = "", [property: FromQuery] string Sort = "name-asc"); private static async Task HandleAsync( Query q, HttpContext ctx, ProductService products, CancellationToken ct) { var items = await products.FilterAsync(q.Category, q.Sort, ct); return await ctx.WriteHtmxPage( new FilterProductsPage(items, q.Category, q.Sort), title: "Products"); } } ```