Corex.Checkbox (Corex v0.1.0-beta.5)

View Source

Phoenix implementation of Zag.js Checkbox.

## Anatomy

### Minimal

  <.checkbox class="checkbox">
    <:label>Accept terms</:label>
  </.checkbox>

### Custom Control

  <.checkbox class="checkbox">
    <:label>
      Accept the terms
    </:label>
    <:indicator>
      <.heroicon name="hero-check" />
    </:indicator>
    <:indeterminate>
      <.heroicon name="hero-minus" />
    </:indeterminate>
  </.checkbox>

### Custom Error

  <.checkbox class="checkbox">
    <:label>
      Accept the terms
    </:label>
    <:error :let={msg}>
      <.heroicon name="hero-exclamation-circle" class="icon" />
      {msg}
    </:error>
  </.checkbox>

## API

See API. Use a stable id on the checkbox with Corex.Checkbox.set_checked/2, set_checked/3, toggle_checked/1, and toggle_checked/2.

DOM CustomEventdetail
corex:checkbox:set-checkedchecked - boolean; clears indeterminate
corex:checkbox:toggle-checked(empty) - toggles checked
  <.action phx-click={Corex.Checkbox.set_checked("my-checkbox", true)}>Check</.action>
  <.action phx-click={Corex.Checkbox.toggle_checked("my-checkbox")}>Toggle</.action>
  def handle_event("check", _, socket),
    do: {:noreply, Corex.Checkbox.set_checked(socket, "my-checkbox", true)}

  def handle_event("toggle", _, socket),
    do: {:noreply, Corex.Checkbox.toggle_checked(socket, "my-checkbox")}

## Events

See Events.

From imperative helpers the hook receives checkbox_set_checked (%{"id" => ..., "checked" => boolean}) and checkbox_toggle_checked (%{"id" => ...}).

Declarative checked may be true, false, or :indeterminate (Zag CheckedState). Imperative set_checked remains boolean-only.

## Styling

Use data attributes to target elements:

  [data-scope="checkbox"][data-part="root"] {}
  [data-scope="checkbox"][data-part="control"] {}
  [data-scope="checkbox"][data-part="label"] {}
  [data-scope="checkbox"][data-part="hidden-input"] {}
  [data-scope="checkbox"][data-part="error"] {}

If you wish to use the default Corex styling, you can use the class checkbox on the component. This requires to install Mix.Tasks.Corex.Design first and import the component css file.

  @import "../corex/main.css";
  @import "../corex/tokens/themes/neo/light.css";
  @import "../corex/components/checkbox.css";

You can then use modifiers:

  <.checkbox class="checkbox checkbox--accent checkbox--lg" />

## Form

When using with Phoenix forms, set the form id in to_form/2 and use id={@form.id} on <.form>.

### Controller

Build the form from an Ecto changeset and pass it to the template. Pass id into to_form/2 so the template can use id={@form.id}:

  def checkbox_form_page(conn, _params) do
    form =
      %MyApp.Form.Terms{}
      |> MyApp.Form.Terms.changeset(%{})
      |> Phoenix.Component.to_form(as: :terms, id: "checkbox-form")
    render(conn, :checkbox_form_page, form: form)
  end
  <.form :let={f} for={@form} id={@form.id} action={@action} method="post">
    <.checkbox field={f[:terms]} class="checkbox">
      <:label>Accept terms</:label>
      <:error :let={msg}>
        <.heroicon name="hero-exclamation-circle" class="icon" />
        {msg}
      </:error>
    </.checkbox>
    <button type="submit">Submit</button>
  </.form>

### Live View

When using Phoenix form in a Live view you must also add controlled mode. Prefer building the form from an Ecto changeset (see "With Ecto changeset" below).

### With Ecto changeset (LiveView)

When using an Ecto changeset for validation in a LiveView, enable the controlled attribute on the checkbox so the LiveView remains the source of truth.

Schema and changeset:

  defmodule MyApp.Form.Terms do
    use Ecto.Schema
    import Ecto.Changeset

    embedded_schema do
      field :terms, :boolean, default: false
    end

    def changeset(terms, attrs \\ %{}) do
      terms
      |> cast(attrs, [:terms])
      |> validate_required([:terms])
      |> validate_acceptance(:terms)
    end
  end

LiveView with validate and submit:

  defmodule MyAppWeb.CheckboxFormLive do
    use MyAppWeb, :live_view
    alias MyApp.Form.Terms

    def mount(_params, _session, socket) do
      form = %Terms{} |> Terms.changeset(%{}) |> to_form(as: :terms, id: "checkbox-form-terms")
      {:ok, assign(socket, :form, form)}
    end

    def handle_event("validate", %{"terms" => params}, socket) do
      changeset = Terms.changeset(%Terms{}, params)
      {:noreply, assign(socket, :form, to_form(changeset, action: :validate, as: :terms, id: "checkbox-form-terms"))}
    end

    def handle_event("save", %{"terms" => params}, socket) do
      case Terms.changeset(%Terms{}, params) do
        %Ecto.Changeset{valid?: true} = _ ->
          {:noreply, assign(socket, :form, to_form(Terms.changeset(%Terms{}, %{}), as: :terms, id: "checkbox-form-terms"))}
        changeset ->
          {:noreply, assign(socket, :form, to_form(changeset, action: :insert, as: :terms, id: "checkbox-form-terms"))}
      end
    end

    def render(assigns) do
      ~H"""
      <.form for={@form} id={@form.id} phx-change="validate" phx-submit="save">
        <.checkbox field={@form[:terms]} class="checkbox" controlled>
          <:label>Accept terms</:label>
          <:error :let={msg}>
            <.heroicon name="hero-exclamation-circle" class="icon" />
            {msg}
          </:error>
        </.checkbox>
        <button type="submit">Submit</button>
      </.form>
      """
    end
  end

Summary

Components

Renders a checkbox component.

API

Sets the checkbox checked state from client-side. Returns a Phoenix.LiveView.JS command.

Sets the checkbox checked state from server-side. Pushes a LiveView event.

Toggles the checkbox checked state from client-side. Returns a Phoenix.LiveView.JS command.

Toggles the checkbox checked state from server-side. Pushes a LiveView event.

Components

checkbox(assigns)

Renders a checkbox component.

Attributes

  • id (:string) - The id of the checkbox, useful for API to identify the checkbox.
  • checked (:any) - Checked state: true, false, or :indeterminate (Zag CheckedState). Form fields still use boolean. Defaults to false.
  • controlled (:boolean) - Whether the checkbox is controlled. Defaults to false.
  • name (:string) - The name of the checkbox input for form submission.
  • form (:string) - The form id to associate the checkbox with.
  • aria_label (:string) - The accessible label for the checkbox. Defaults to "Label".
  • disabled (:boolean) - Whether the checkbox is disabled. Defaults to false.
  • value (:string) - The value of the checkbox when checked. Defaults to "true".
  • dir (:string) - The direction of the checkbox. When nil, derived from document (html lang + config :rtl_locales). Defaults to nil. Must be one of nil, "ltr", or "rtl".
  • orientation (:string) - Layout orientation for CSS (vertical or horizontal). Defaults to "horizontal". Must be one of "vertical", or "horizontal".
  • read_only (:boolean) - Whether the checkbox is read-only. Defaults to false.
  • invalid (:boolean) - Whether the checkbox has validation errors. Defaults to false.
  • required (:boolean) - Whether the checkbox is required. Defaults to false.
  • on_checked_change (:string) - The server event name when the checked state changes. Defaults to nil.
  • on_checked_change_client (:string) - The client event name when the checked state changes. Defaults to nil.
  • errors (:list) - List of error messages to display. Defaults to [].
  • field (Phoenix.HTML.FormField) - A form field struct retrieved from the form, for example: @form[:email]. Automatically sets id, name, checked state, and errors from the form field.
  • Global attributes are accepted.

Slots

  • label - Accepts attributes:
    • class (:string)
  • indicator - Accepts attributes:
    • class (:string)
  • indeterminate - Accepts attributes:
    • class (:string)
  • error - Accepts attributes:
    • class (:string)

API

set_checked(checkbox_id, checked)

Sets the checkbox checked state from client-side. Returns a Phoenix.LiveView.JS command.

Examples

<button phx-click={Corex.Checkbox.set_checked("my-checkbox", true)}>
  Check
</button>

<button phx-click={Corex.Checkbox.set_checked("my-checkbox", false)}>
  Uncheck
</button>

set_checked(socket, checkbox_id, checked)

Sets the checkbox checked state from server-side. Pushes a LiveView event.

Examples

def handle_event("check", _params, socket) do
  socket = Corex.Checkbox.set_checked(socket, "my-checkbox", true)
  {:noreply, socket}
end

toggle_checked(checkbox_id)

Toggles the checkbox checked state from client-side. Returns a Phoenix.LiveView.JS command.

Examples

<button phx-click={Corex.Checkbox.toggle_checked("my-checkbox")}>
  Toggle
</button>

toggle_checked(socket, checkbox_id)

Toggles the checkbox checked state from server-side. Pushes a LiveView event.

Examples

def handle_event("toggle", _params, socket) do
  socket = Corex.Checkbox.toggle_checked(socket, "my-checkbox")
  {:noreply, socket}
end

Functions

checkbox_skeleton(assigns)

Attributes

  • skeleton_label (:boolean) - When true, renders a compact label-line placeholder (same line height band as the real checkbox label). Defaults to true.
  • dir (:string) - Same as checkbox: logical direction for layout. Defaults to nil. Must be one of nil, "ltr", or "rtl".
  • orientation (:string) - Same as checkbox: layout orientation for the skeleton root. Defaults to "horizontal". Must be one of "vertical", or "horizontal".
  • Global attributes are accepted.