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 CustomEvent | detail |
|---|---|
corex:checkbox:set-checked | checked - 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
endLiveView 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
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 tofalse.controlled(:boolean) - Whether the checkbox is controlled. Defaults tofalse.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 tofalse.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 tonil. Must be one ofnil,"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 tofalse.invalid(:boolean) - Whether the checkbox has validation errors. Defaults tofalse.required(:boolean) - Whether the checkbox is required. Defaults tofalse.on_checked_change(:string) - The server event name when the checked state changes. Defaults tonil.on_checked_change_client(:string) - The client event name when the checked state changes. Defaults tonil.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
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>
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
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>
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
Attributes
skeleton_label(:boolean) - When true, renders a compact label-line placeholder (same line height band as the real checkbox label). Defaults totrue.dir(:string) - Same as checkbox: logical direction for layout. Defaults tonil. Must be one ofnil,"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.