# Checkbox A styled checkbox input with an optional visible label. Uses the `accent-primary` Tailwind class so the checkmark color follows your primary theme color. --- ## HTML structure ``` div.flex.items-center.space-x-2 input[type=checkbox, id, name, value, class, $$Checked$$] label[for={id}] ← omitted when label is empty {label text} ``` --- ## CSS mechanics | Class | Effect | |---|---| | `accent-primary` | Checkmark color follows the `--color-primary` CSS variable | | `h-4 w-4 rounded` | Consistent 16×16 size with slightly rounded corners | | `cursor-pointer` | Pointer cursor on label | | `text-sm font-medium leading-none peer-disabled:opacity-70` | Standard label styling | --- ## Constructor signature ```csharp public Checkbox( string id, string label = "", string name = "", string value = "true", bool @checked = false) ``` | Parameter | Description | |---|---| | `id` | Element id and the `for` attribute on the label | | `label` | Visible text next to the checkbox; omit for a standalone checkbox | | `name` | Form field name (required when used in a form) | | `value` | Submitted value when checked (default: `"true"`) | | `checked` | Pre-checked state | --- ## Usage examples ### Basic opt-in checkbox ```csharp new Checkbox( id: "newsletter", label: "Subscribe to newsletter", name: "newsletter") ``` ### Pre-checked ```csharp new Checkbox( id: "remember", label: "Remember me", name: "rememberMe", checked: true) ``` ### No visible label ```csharp new Checkbox(id: "select-all", name: "selectAll") ``` ### Custom submitted value ```csharp new Checkbox( id: "agree", label: "I agree to the terms", name: "terms", value: "accepted") ``` ### Reading in a form handler ```csharp public record Command( [property: FromForm] string? Newsletter = null, // null when unchecked [property: FromForm] string? RememberMe = null ); bool wantsNewsletter = command.Newsletter == "true"; bool rememberUser = command.RememberMe == "true"; ``` > Note: Unchecked checkboxes are not included in form data. Always use a nullable string or a default value of `null`. --- ## Tips and tricks - Because HTML forms only submit checked checkboxes, pair a checkbox with a hidden input of the same name and value `"false"` if you need the unchecked state explicitly in your command. - The label `for` attribute ties to the `id`, so clicking the label text toggles the checkbox — always set `id`. - If you need multi-select (select multiple rows in a table), use the same `name` for all checkboxes; they will be submitted as a comma-separated list or multiple values depending on form binding. - `accent-primary` is a modern CSS property — all current browsers support it. - `accent-primary` is a modern CSS property — all current browsers support it. --- ## Complete page example **`Templates/PreferencesPage.htmx`** ```html

Preferences

$$AntiforgeryToken$$
$$NewsletterCheck$$ $$MarketingCheck$$ $$RememberCheck$$
$$SaveBtn$$
$$SuccessAlert$$
``` **`Templates/PreferencesPage.htmx.cs`** ```csharp namespace Htmx.ApiDemo.Templates; public sealed class PreferencesPage : PreferencesPageBase { private readonly IHtmxComponent _newsletter; private readonly IHtmxComponent _marketing; private readonly IHtmxComponent _remember; private readonly IHtmxComponent _save; private readonly IHtmxComponent _success; private readonly byte[] _afToken; public PreferencesPage( IAntiforgery af, HttpContext ctx, UserPrefs? prefs = null, bool saved = false) { var tokens = af.GetAndStoreTokens(ctx); _afToken = $"""""".ToUtf8Bytes(); _newsletter = new Components.Checkbox( id: "newsletter", label: "Receive newsletter", name: "newsletter", @checked: prefs?.Newsletter ?? false); _marketing = new Components.Checkbox( id: "marketing", label: "Receive marketing emails", name: "marketing", @checked: prefs?.Marketing ?? false); _remember = new Components.Checkbox( id: "remember", label: "Keep me signed in", name: "remember", @checked: prefs?.Remember ?? false); _save = new Components.Button("Save preferences", type: "submit"); _success = saved ? new Components.Alert(title: "Preferences saved.") : HtmxEmpty.Instance; } protected override void RenderAntiforgeryToken(HtmxRenderContext ctx) => ctx.Writer.WriteUtf8(_afToken); protected override void RenderNewsletterCheck(HtmxRenderContext ctx) => _newsletter.Render(ctx.Next()); protected override void RenderMarketingCheck(HtmxRenderContext ctx) => _marketing.Render(ctx.Next()); protected override void RenderRememberCheck(HtmxRenderContext ctx) => _remember.Render(ctx.Next()); protected override void RenderSaveBtn(HtmxRenderContext ctx) => _save.Render(ctx.Next()); protected override void RenderSuccessAlert(HtmxRenderContext ctx) => _success.Render(ctx.Next()); } ``` **POST handler** ```csharp [Handler] [MapPost("/preferences")] public static partial class PostPreferencesHandler { public record Command( [property: FromForm] string? Newsletter = null, [property: FromForm] string? Marketing = null, [property: FromForm] string? Remember = null); private static Task HandleAsync( [AsParameters] Command cmd, HttpContext ctx, IAntiforgery af, CancellationToken ct) { var prefs = new UserPrefs( Newsletter: cmd.Newsletter != null, Marketing: cmd.Marketing != null, Remember: cmd.Remember != null); // Persist prefs… return ctx.WriteHtmxPage(new PreferencesPage(af, ctx, prefs, saved: true), title: "Preferences"); } } public record UserPrefs(bool Newsletter, bool Marketing, bool Remember); ``` **`AppJsonSerializerContext.cs`** ```csharp [JsonSerializable(typeof(PostPreferencesHandler.Command), TypeInfoPropertyName = "PreferencesCommand")] ```