defmodule RiverConnectWeb.Components.UI.Form do
@moduledoc """
Form-related components that help build accessible forms.
SaladUI doesn't define its own form component, but instead provides a set of
form-related components to enhance the native Phoenix LiveView form.
## Examples:
<.form
class="space-y-6"
for={@form}
id="project-form"
phx-target={@myself}
phx-change="validate"
phx-submit="save"
>
<.form_item>
<.form_label>What is your project's name?
<.form_control>
<.input field={@form[:name]} type="text" phx-debounce="500" />
<.form_description>
This is your public display name.
<.form_message field={@form[:name]} />
<.button
class="btn btn-secondary btn-md"
icon="inbox_arrow_down"
phx-disable-with="Saving..."
>
Save project
"""
use RiverConnectWeb.Components.UI, :component
@doc """
Form item component that acts as a container for a form field.
## Examples:
<.form_item>
<.form_label>Email
<.form_control>
<.input field={@form[:email]} type="email" />
<.form_message field={@form[:email]} />
"""
attr :class, :string, default: nil
slot :inner_block, required: true
attr :rest, :global
def form_item(assigns) do
~H"""
{render_slot(@inner_block)}
"""
end
@doc """
Form label component that renders a label for a form field.
Shows validation errors through text color when a field has errors.
## Examples:
<.form_label>Email
<.form_label field={@form[:email]}>Email
"""
attr :class, :string, default: nil
attr :field, Phoenix.HTML.FormField,
default: nil,
doc: "a form field struct retrieved from the form, for example: @form[:email]"
attr :for, :string, default: nil
attr :error, :boolean, default: false, doc: "whether the field has an error"
slot :inner_block, required: true
attr :rest, :global
def form_label(assigns) do
assigns = assign(assigns, error: assigns[:error] || has_error?(assigns[:field]))
~H"""
{render_slot(@inner_block)}
"""
end
@doc """
Form control component that wraps input elements.
This is a simple pass-through component that renders its inner block.
## Examples:
<.form_control>
<.input field={@form[:email]} type="email" />
"""
slot :inner_block, required: true
def form_control(assigns) do
~H"""
{render_slot(@inner_block)}
"""
end
@doc """
Form description component that provides additional context for a form field.
## Examples:
<.form_description>
We'll only use your email for account-related purposes.
"""
attr :class, :string, default: nil
slot :inner_block, required: true
attr :rest, :global
def form_description(assigns) do
~H"""
{render_slot(@inner_block)}
"""
end
@doc """
Form message component that displays validation errors for a form field.
## Examples:
<.form_message field={@form[:email]} />
<.form_message>
Please enter a valid email address.
"""
attr :field, Phoenix.HTML.FormField,
default: nil,
doc: "a form field struct retrieved from the form, for example: @form[:email]"
attr :errors, :any,
default: [],
doc: "a list of error messages to display"
attr :class, :string, default: nil
slot :inner_block, required: false
attr :rest, :global
def form_message(assigns) do
assigns =
assigns
|> assign(error: has_error?(assigns[:field]) || not Enum.empty?(assigns[:errors]))
|> assign(:message, List.first(assigns[:errors] || field_errors(assigns[:field])))
~H"""
{msg || @message}
"""
end
end