Fluxon.Components.Checkbox (Fluxon v3.0.0)

Checkbox inputs for boolean toggles, opt-in confirmations, and multi-select option lists.

Renders both single checkboxes and grouped checkbox lists with built-in label, sublabel, description, and error rendering. Integrates directly with Phoenix forms via the field attribute, and ships a card variant for richer selection surfaces such as plan pickers, feature toggles, or day-of-week selectors.

Choosing between checkbox and related inputs

ComponentBest suited for
checkbox/1Single boolean opt-in (terms, marketing, "remember me").
checkbox_group/1Multi-select from a known set of options into a single form field.
Fluxon.Components.RadioSingle-selection from a mutually exclusive set of options.
Fluxon.Components.SwitchOn/off toggle for an immediately applied setting.

Usage

The simplest form takes a name and a label:

<.checkbox name="terms" label="I agree to the terms and conditions" />

By default the checkbox submits "true" when checked and "false" when unchecked. Both values are always present in the form payload because a hidden input mirrors the field name with the unchecked value:

# checked
%{"terms" => "true"}

# unchecked (hidden input still submits)
%{"terms" => "false"}

Override the wire values with checked_value and unchecked_value to match the schema the server expects:

<.checkbox name="active" label="Active" checked_value="1" unchecked_value="0" />

Add sublabel for a short inline qualifier and description for longer explanatory copy rendered beneath the label:

<.checkbox
  name="notifications"
  label="Enable notifications"
  sublabel="Recommended"
  description="We'll send you important updates about your account status and security."
/>

Form Integration

The component offers two ways to wire form data: the field attribute for Phoenix form bindings, or the name attribute for standalone controls.

Pass a Phoenix.HTML.FormField to field and the component derives id, name, the current value, and any validation errors automatically. Errors are only shown after the field has been used (Phoenix.Component.used_input?/1), matching the convention used across the rest of Fluxon's form inputs.

<.form :let={f} for={@form} phx-change="validate" phx-submit="save">
  <.checkbox
    field={f[:marketing_emails]}
    label="Marketing emails"
    sublabel="Receive updates about new features and promotions"
  />

  <.checkbox
    field={f[:terms_accepted]}
    label="Terms and Conditions"
    description="I agree to the terms of service and privacy policy"
  />

  <.checkbox
    field={f[:active]}
    label="Active user"
    checked_value="1"
    unchecked_value="0"
  />
</.form>

Using standalone checkboxes

When not bound to a form, supply name, manage checked yourself, and pass any error messages explicitly through errors:

<.checkbox
  name="show_archived"
  checked={@show_archived}
  label="Show archived items"
/>

<.checkbox
  name="user[preferences][dark_mode]"
  checked={@user_preferences.dark_mode}
  errors={@errors["dark_mode"]}
  label="Dark mode"
  sublabel="Use dark theme"
/>

When to use each approach

Use field when working with changesets, validation messages, nested associations, or any CRUD form. Use name for standalone toggles such as table filters, page-level preferences, or controls that drive phx-change handlers without a backing schema.

Checked State Resolution

How the rendered checked attribute is computed depends on which inputs you provide:

Inputs suppliedResolution
checked (boolean)Used verbatim. Wins over value comparisons.
field and no checkedfield.value compared (as escaped HTML) against checked_value.
value and no checkedvalue compared against checked_value.
Neither value nor checkedRenders unchecked.

The comparison uses Phoenix.HTML.html_escape/1 on both sides, so integers and strings with the same string representation match (for example value={1} against checked_value="1").

Variants

The variant attribute controls the surrounding chrome:

  • nil (default): Standard checkbox aligned next to its label, sublabel, and description. Use for inline opt-ins, settings rows, and the bulk of form fields.
  • "card": The entire row becomes a clickable card that highlights when checked. Use when you want each option to feel like a tappable surface, for example in plan selectors, feature pickers, or onboarding flows.

In the card variant, control positions the checkbox input within the card:

  • "left": Checkbox on the leading edge, label content trailing. Default-feeling layout for option lists.
  • "right": Checkbox on the trailing edge, label content leading. Useful when the label carries the primary visual weight (titles, icons, prices).

When neither value is set in the card variant, the checkbox input is visually hidden (sr-only) and the entire card surface communicates the checked state. This is the pattern used by the weekday selector example below.

Examples

Confirmation checkbox bound to a changeset:

<.form :let={f} for={@form} phx-submit="register">
  <.checkbox
    field={f[:terms_accepted]}
    label="I accept the Terms of Service"
    description="You must agree before creating an account."
  />
  <.button type="submit">Create account</.button>
</.form>

Filter toggle wired directly to a LiveView event:

<.checkbox
  name="show_archived"
  checked={@show_archived}
  label="Show archived"
  phx-click="toggle_archived"
/>

Plan selector using the card variant with custom inner content:

<.checkbox name="plan" variant="card" checked_value="pro" unchecked_value="free">
  <div>
    <h3 class="font-semibold">Pro plan</h3>
    <p class="text-sm text-foreground-muted">$19 / month, billed annually.</p>
  </div>
</.checkbox>

Group of notification channels bound to a form field:

<.checkbox_group
  field={f[:notification_channels]}
  label="Notifications"
  description="Choose how you want to be notified."
>
  <:checkbox value="email" label="Email" sublabel="Daily digest" />
  <:checkbox value="push" label="Push" sublabel="Real-time alerts" />
  <:checkbox value="sms" label="SMS" sublabel="Critical events only" disabled />
</.checkbox_group>

Day-of-week picker rendered as compact cards:

<.checkbox_group
  field={f[:weekdays]}
  variant="card"
  label="Working days"
  class="flex gap-x-2"
>
  <:checkbox
    :for={{label, value} <- [{"S", "sun"}, {"M", "mon"}, {"T", "tue"}, {"W", "wed"}, {"T", "thu"}, {"F", "fri"}, {"S", "sat"}]}
    value={value}
    class="flex items-center justify-center rounded-full has-checked:bg-zinc-800 text-zinc-700 has-checked:text-white size-10"
  >
    <span class="text-sm font-medium">{label}</span>
  </:checkbox>
</.checkbox_group>

Checkbox Groups

checkbox_group/1 maps a list of :checkbox slot entries to a single form field that collects every selected value. The component appends [] to the supplied name so the server receives a list, and renders an additional hidden input with an empty value so the field is always present in the form payload.

<.checkbox_group
  name="preferences"
  label="Notification preferences"
  description="Choose when you want to receive notifications"
>
  <:checkbox value="email" label="Email notifications" />
  <:checkbox value="push" label="Push notifications" />
  <:checkbox value="sms" label="SMS notifications" />
</.checkbox_group>

Each :checkbox slot accepts its own value, label, sublabel, description, disabled, checked, and class, plus an optional inner block (used by the card variant to swap the default label structure for custom content). The slot's checked is honored in addition to membership in the group's bound value list, so you can pre-check individual options independent of the form state.

Empty values in checkbox groups

Browsers only submit values for boxes that are actually checked. To keep the field present in form data even when nothing is selected, the group renders a hidden input with an empty string value:

<input type="hidden" name="preferences[]" value="" />

Submissions therefore look like one of:

# nothing selected
%{"preferences" => [""]}

# one or more selected
%{"preferences" => ["", "email", "push"]}

Filter the empty string in your handler before treating the value as the user's choice:

selected = Enum.reject(params["preferences"] || [], &(&1 == ""))

Disabled State

Setting disabled on checkbox/1 or checkbox_group/1 disables the underlying input(s) and propagates the disabled style to label, sublabel, and description. On the single checkbox, the hidden mirror input is also marked disabled so the field is omitted from the submitted payload, matching native HTML form behavior.

Group items can be disabled individually by setting disabled on a :checkbox slot, leaving the rest of the group interactive.

Form Attribute

Both components forward a form attribute through :rest to the rendered inputs and to the hidden mirror input(s). Use it when the checkbox lives outside the <form> element it belongs to:

<.checkbox name="agree" label="I agree" form="signup-form" />

Summary

Components

Renders a single checkbox input alongside its label, sublabel, description, and errors.

Renders a group of checkboxes that collect multiple selections into a single form field.

Components

checkbox(assigns)

Renders a single checkbox input alongside its label, sublabel, description, and errors.

Use for boolean opt-ins (terms acceptance, marketing consent, "remember me") and any field that maps to a single value. The component renders a hidden mirror input with the unchecked value so the field is always present in submitted form data, even when the box is unchecked. Pair with field for Phoenix form binding, or with name for standalone control such as filter toggles or LiveView event handlers.

Attributes

  • id (:any) - Identifier applied to the checkbox <input> and referenced by the <label> for pointer association. When omitted, an ID is generated automatically; a field binding will reuse field.id instead.

    Defaults to nil.

  • name (:any) - Form field name applied to both the checkbox input and its hidden mirror input. Required when field is not provided.

  • checked (:boolean) - Forces the checked state when supplied, taking precedence over any value versus checked_value comparison. Omit to let the component derive the state from value (or from field.value when bound to a form).

  • value (:any) - Current value associated with the field. The component compares it against checked_value (using Phoenix.HTML.html_escape/1 on both sides) to decide whether to render checked. Provided automatically when field is set.

  • checked_value (:any) - Value submitted when the checkbox is checked. Defaults to "true". Override to match the underlying schema, for example "1" for boolean integer columns or domain-specific strings such as "yes" or "accepted".

    <.checkbox name="active" checked_value="1" unchecked_value="0" />
    <.checkbox name="agree" checked_value="yes" unchecked_value="no" />

    Defaults to "true".

  • unchecked_value (:any) - Value submitted via the hidden mirror input when the checkbox is unchecked. Defaults to "false". Browsers do not submit unchecked checkboxes, so this hidden input is what keeps the field present in the payload.

    Defaults to "false".

  • errors (:list) - Error messages to render beneath the checkbox. Populated automatically from validation output when field is supplied and the field has been used; pass explicitly when managing state outside of Phoenix forms.

    Defaults to [].

  • label (:string) - Primary label rendered next to the checkbox. Omit to render only the input, for example when the surrounding markup provides its own labeling.

    Defaults to nil.

  • sublabel (:string) - Short inline qualifier rendered beside the main label (for example "Optional", "Recommended"). Has no effect when label is nil.

    Defaults to nil.

  • description (:string) - Longer explanatory copy rendered beneath the label. Use to provide context the label alone cannot carry.

    Defaults to nil.

  • class (:any) - Extra classes merged onto the rendered surface. In the standard variant they apply to the checkbox <input>; in the card variant they apply to the wrapping <label> so you can restyle the card itself (background, radius, sizing).

    Defaults to nil.

  • field (Phoenix.HTML.FormField) - Phoenix form field to bind to. When provided, the component derives id, name, value, and errors from the field.

  • variant (:string) - Visual chrome around the checkbox.

    • nil (default): Standard checkbox aligned next to its label and description. Use for inline opt-ins and most form fields.
    • "card": The whole row becomes a clickable card surface that highlights when checked. Use for richer selections such as plan pickers or feature toggles.

    Defaults to nil.

  • control (:string) - Position of the checkbox input within the card. Only meaningful when variant="card".

    • "left": Checkbox leads, label content trails.
    • "right": Checkbox trails, label content leads.

    When omitted in the card variant, the checkbox input is visually hidden and the card surface communicates the checked state on its own.

Must be one of "left", or "right".

  • Global attributes are accepted. Additional HTML attributes forwarded to the checkbox <input>. disabled propagates to the hidden mirror input as well, so a disabled checkbox is excluded from the submitted payload. form is forwarded to both inputs, allowing the checkbox to live outside the <form> element it belongs to. Supports all globals plus: ["disabled", "form"].

Slots

  • inner_block - Custom content rendered inside the card surface in place of the default label/sublabel/description structure. Only meaningful when variant="card"; ignored by the standard variant.

checkbox_group(assigns)

Renders a group of checkboxes that collect multiple selections into a single form field.

Use this when a single field on the form (a list column, an array of associations, a multi-select preference) should be populated from several related options. Each option is declared via a :checkbox slot entry; the component takes care of suffixing the field name with [], keeping the field present in the payload via a hidden empty input, and rendering label, description, and error messages around the group.

Pair with the field attribute for automatic Phoenix form binding, or use name plus value for standalone control.

Attributes

  • id (:any) - Identifier applied to the group. Each :checkbox slot input derives its id by appending its index (for example "id-0"). When omitted, an ID is generated automatically; a field binding will reuse field.id instead.

    Defaults to nil.

  • name (:string) - Form field name for the group. The component appends [] so the server receives a list. Required when field is not provided.

  • value (:any) - List of currently selected values. Each :checkbox slot whose value is a member of this list renders pre-checked. Defaults to [] when omitted, or to field.value (or [] if nil) when bound via field.

  • label (:string) - Heading rendered above the checkboxes via Fluxon.Components.Form.label/1. Omit to render the group without a heading, for example when the surrounding layout already provides one.

    Defaults to nil.

  • sublabel (:string) - Short qualifier rendered alongside the main label (for example "Optional", "Recommended"). Has no effect when label is nil.

    Defaults to nil.

  • description (:string) - Longer explanatory copy rendered beneath the label. Use to clarify what the group is for or how the selection will be used.

    Defaults to nil.

  • errors (:list) - Error messages to render beneath the group. Populated automatically from validation output when field is supplied and the field has been used; pass explicitly when managing state outside of Phoenix forms.

    Defaults to [].

  • class (:any) - Extra classes applied to the inner container that holds the checkboxes. Use this to switch the layout from the default stacked column to, for example, a horizontal row ("flex gap-x-2") or a multi-column grid.

    Defaults to nil.

  • field (Phoenix.HTML.FormField) - Phoenix form field to bind to. When provided, the component derives id, name, value, and errors from the field.

  • disabled (:boolean) - Disables every checkbox in the group when true. Individual options can still be disabled via the :checkbox slot's own disabled attribute regardless of this value.

    Defaults to false.

  • variant (:string) - Visual chrome wrapping each option.

    • nil (default): Standard stacked checkboxes with label, sublabel, and description. Use for typical multi-select form fields.
    • "card": Each option becomes a clickable card surface that highlights when checked. Use for richer pickers (feature toggles, day selectors, plan options).

    Defaults to nil.

  • control (:string) - Position of the checkbox input within each card. Only meaningful when variant="card".

    • "left": Checkbox leads, label content trails. Default-feeling for option lists.
    • "right": Checkbox trails, label content leads. Use when the label carries the primary visual weight.

    When omitted in the card variant, the checkbox input is visually hidden and the entire card surface communicates the checked state.

Must be one of "left", or "right".

  • Global attributes are accepted. Additional HTML attributes forwarded to every checkbox <input> in the group. The form attribute is also forwarded to the hidden empty-value input so the group stays associated with the correct form when rendered outside of it. Supports all globals plus: ["disabled", "form"].

Slots

  • checkbox (required) - One entry per option in the group. The slot's inner block, when present, is rendered inside the card surface in place of the default label structure (only meaningful with variant="card").Accepts attributes:
    • value (:any) (required) - Value submitted when this option is checked, and used to compute initial state.

    • label (:string) - Primary label rendered next to (or inside) the option.

    • sublabel (:string) - Short inline qualifier rendered beside the option's label.

    • description (:string) - Longer explanatory copy rendered beneath the option's label.

    • disabled (:boolean) - Disables this option independently of the group-level disabled flag.

    • class (:any) - Extra classes applied to the option. In the standard variant they are merged onto the checkbox <input>; in the card variant they are merged onto the card <label>.

    • checked (:boolean) - Forces this option's initial checked state regardless of group value membership. Use to seed pre-checked options when not driven by form data.