Forms
Hybrid Form
A LiveView form with a React control inside it
- forms
- Phoenix.HTML.Form encoder
Key concepts
A React component can sit inside an ordinary <.simple_form>
alongside HEEx inputs, as long as it renders a field named the way
Phoenix.HTML.Form
expects. It doesn't need pushEvent
at all — the field's value reaches phx-change
the same
way any native input's would.
defmodule MyAppWeb.HybridFormLive do
use MyAppWeb, :live_view
def mount(_params, _session, socket) do
form =
to_form(%{"email" => "hello@mrdotb.com", "delay_between" => [4_000, 30_000]}, as: :settings)
{:ok, assign(socket, form: form)}
end
def render(assigns) do
~H"""
<.simple_form id="settings-form" for={@form} phx-change="validate" phx-submit="submit">
<.input field={@form[:email]} label="Email" />
<.react
name="HybridForm"
inputName="settings[delay_between]"
value={@form[:delay_between].value}
min={2_000}
max={90_000}
step={2_000}
socket={@socket}
/>
<:actions>
<.button>Save</.button>
</:actions>
</.simple_form>
"""
end
def handle_event("validate", %{"settings" => settings}, socket) do
form = to_form(settings, as: :settings, action: :validate)
{:noreply, assign(socket, form: form)}
end
def handle_event("submit", _params, socket) do
{:noreply, socket}
end
endHow it works
The slider passes inputName="settings[delay_between]"
straight through to Radix's name
prop, which renders
hidden inputs under that name for each thumb. The browser submits
them like any other form field, so phx-change="validate"
fires exactly as it would for a native <input>.
The component's own dragging state — the thumb positions mid-drag —
lives in useState and never touches the server; only a
real change event submits a value, same as a native range input.