ee8797c142
Co-authored-by: Copilot <copilot@github.com>
6.3 KiB
6.3 KiB
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
forattribute ties to theid, so clicking the label text toggles the checkbox — always setid. - If you need multi-select (select multiple rows in a table), use the same
namefor all checkboxes; they will be submitted as a comma-separated list or multiple values depending on form binding. accent-primaryis a modern CSS property — all current browsers support it.accent-primaryis 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")]