Files
Htmx/docs/Components/Checkbox.md
T
2026-05-04 19:57:48 +05:00

6.3 KiB
Raw Blame History

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

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

new Checkbox(
    id:    "newsletter",
    label: "Subscribe to newsletter",
    name:  "newsletter")

Pre-checked

new Checkbox(
    id:      "remember",
    label:   "Remember me",
    name:    "rememberMe",
    checked: true)

No visible label

new Checkbox(id: "select-all", name: "selectAll")

Custom submitted value

new Checkbox(
    id:    "agree",
    label: "I agree to the terms",
    name:  "terms",
    value: "accepted")

Reading in a form handler

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

<div class="max-w-md mx-auto py-10">
  <h1 class="text-2xl font-bold mb-6">Preferences</h1>
  <form method="post" action="/preferences">
    $$AntiforgeryToken$$
    <div class="space-y-4 mb-6">
      $$NewsletterCheck$$
      $$MarketingCheck$$
      $$RememberCheck$$
    </div>
    $$SaveBtn$$
  </form>
  $$SuccessAlert$$
</div>

Templates/PreferencesPage.htmx.cs

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 = $"""<input type="hidden" name="{tokens.FormFieldName}" value="{tokens.RequestToken}">""".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

[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<IResult> 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

[JsonSerializable(typeof(PostPreferencesHandler.Command), TypeInfoPropertyName = "PreferencesCommand")]