Corex.Toggle (Corex v0.2.0)

View Source

Toggle button for Phoenix LiveView. Behavior follows Zag.js Toggle.

Anatomy

Minimal

<.toggle class="toggle">
  lorem
</.toggle>

With indicator

<.toggle class="toggle">
  <:indicator><.heroicon name="hero-bold" /></:indicator>
  Bold
</.toggle>

<.toggle class="toggle">
  <:indicator><.heroicon name="hero-bold" /></:indicator>
  <span class="sr-only">Bold</span>
</.toggle>

Dual label

Set data-toggle-dual-label on the host to swap visible label text when pressed. Use a second <span data-pressed> for the on-state label.

<.toggle class="toggle" data-toggle-dual-label>
  <span>lorem</span>
  <span data-pressed>donec</span>
</.toggle>

API

Requires a stable id on <.toggle>.

FunctionActionReturns
set_pressed/2Set pressed state (client)%Phoenix.LiveView.JS{}
set_pressed/3Set pressed state (server)socket
toggle_pressed/2Toggle pressed (client)%Phoenix.LiveView.JS{}
toggle_pressed/3Toggle pressed (server)socket

Events

Pick an event name and pass it to on_* on <.toggle>.

Server events

EventWhenPayload
on_pressed_change="toggle_pressed_changed"Pressed state changes%{"id" => id, "pressed" => boolean}

on_pressed_change

<.toggle
  class="toggle"
  controlled
  pressed={false}
  on_pressed_change="toggle_pressed_changed"
>
  lorem
</.toggle>
def handle_event("toggle_pressed_changed", %{"pressed" => pressed}, socket) do
  p = pressed == true or pressed == "true"
  {:noreply, assign(socket, :pressed, p)}
end

Client events

EventWhenevent.detail
on_pressed_change_client="toggle-client-changed"Pressed state changesid, pressed

on_pressed_change_client

<.toggle
  id="toggle-on-pressed-change-client"
  class="toggle"
  on_pressed_change_client="toggle-client-changed"
>
  lorem
</.toggle>
const el = document.getElementById("toggle-on-pressed-change-client");
el?.addEventListener("toggle-client-changed", (e) => console.log(e.detail));

Patterns

Controlled

For server-owned pressed state, set controlled, bind pressed, and handle on_pressed_change in LiveView.

<.toggle
  class="toggle"
  controlled
  pressed={@pressed}
  on_pressed_change="toggle_patterns_pressed"
>
  lorem
</.toggle>
def mount(_params, _session, socket) do
  {:ok, assign(socket, :pressed, false)}
end

def handle_event("toggle_patterns_pressed", %{"pressed" => pressed}, socket) do
  {:noreply, assign(socket, :pressed, pressed == true or pressed == "true")}
end

Style

Target parts with data-scope and data-part, or use Corex Design: import tokens and toggle.css, then set class="toggle" on <.toggle>.

[data-scope="toggle"][data-part="root"] {}
[data-scope="toggle"][data-part="indicator"] {}
@import "../corex/corex.css";

Stack modifiers on the host (class on <.toggle>). Combine axes, for example toggle ui-accent ui-size-lg.

Axes: Semantic (ui-accent, ui-brand, ui-alert, ui-info, ui-success), Size (ui-size-smui-size-xl), Radius (ui-rounded-*). No variant axis. See the modifier guide.

Semantic modifiers set palette variables for the filled on state. Off stays neutral. On always fills (--ctl-fill, or ink when no semantic role is set).

Semantic

Palette variables for the filled on state.

ModifierClasses
Defaulttoggle
Accenttoggle ui-accent
Brandtoggle ui-brand
Alerttoggle ui-alert
Infotoggle ui-info
Successtoggle ui-success

Size

ModifierClasses
SMtoggle ui-size-sm
MDtoggle ui-size-md
LGtoggle ui-size-lg
XLtoggle ui-size-xl

Rounded

ModifierClasses
Nonetoggle ui-rounded-none
SMtoggle ui-rounded-sm
MDtoggle ui-rounded-md
LGtoggle ui-rounded-lg
XLtoggle ui-rounded-xl
Fulltoggle ui-rounded-full

Summary

API

Set pressed state from a control (phx-click).

Set pressed state from handle_event.

Flip pressed state from a control (phx-click).

Flip pressed state from handle_event.

Components

toggle(assigns)

Attributes

  • id (:string)
  • pressed (:boolean) - Initial or controlled pressed state. Defaults to false.
  • controlled (:boolean) - Defaults to false.
  • disabled (:boolean) - Defaults to false.
  • dir (:string) - When nil, derived from document. Defaults to nil. Must be one of nil, "ltr", or "rtl".
  • on_pressed_change (:string) - Defaults to nil.
  • on_pressed_change_client (:string) - Defaults to nil.
  • Global attributes are accepted.

Slots

  • inner_block
  • indicator - Accepts attributes:
    • class (:string)

API

set_pressed(toggle_id, pressed)

@spec set_pressed(String.t(), boolean()) :: Phoenix.LiveView.JS.t()

Set pressed state from a control (phx-click).

<.action phx-click={Corex.Toggle.set_pressed("my-toggle", true)}>On</.action>
<.toggle id="my-toggle" class="toggle">Label</.toggle>
document.getElementById("my-toggle")?.dispatchEvent(
  new CustomEvent("corex:toggle:set-pressed", {
    bubbles: false,
    detail: { pressed: true },
  })
);

set_pressed(socket, toggle_id, pressed)

Set pressed state from handle_event.

<.action phx-click="press_toggle">On</.action>
<.toggle id="my-toggle" class="toggle">Label</.toggle>
def handle_event("press_toggle", _, socket) do
  {:noreply, Corex.Toggle.set_pressed(socket, "my-toggle", true)}
end

toggle_pressed(toggle_id)

@spec toggle_pressed(String.t()) :: Phoenix.LiveView.JS.t()

Flip pressed state from a control (phx-click).

<.action phx-click={Corex.Toggle.toggle_pressed("my-toggle")}>Toggle</.action>
<.toggle id="my-toggle" class="toggle">Label</.toggle>
document.getElementById("my-toggle")?.dispatchEvent(
  new CustomEvent("corex:toggle:toggle-pressed", { bubbles: false })
);

toggle_pressed(socket, toggle_id)

Flip pressed state from handle_event.

<.action phx-click="flip_toggle">Toggle</.action>
<.toggle id="my-toggle" class="toggle">Label</.toggle>
def handle_event("flip_toggle", _, socket) do
  {:noreply, Corex.Toggle.toggle_pressed(socket, "my-toggle")}
end