# `PhoenixKitEntities.Components.FieldInput`
[🔗](https://github.com/BeamLabEU/phoenix_kit_entities/blob/v0.4.6/lib/phoenix_kit_entities/components/field_input.ex#L1)

Control-only inline renderer for ONE entity field — the embeddable
primitive under `FormBuilder.build_field/3`'s full form blocks. Hosts
that lay records out their own way (compact rows, table cells, chips)
render `<.field_input>` per field and keep full ownership of layout,
labels, and persistence, while every field type — including ones added
to entities later — renders correctly without host changes.

## The save contract

The host wraps its inputs in a `<form phx-change="..." phx-submit="...">`
it owns (include hidden inputs for row identity — a record uuid — and
read `_target` to know which field changed). **`phx-submit` is
load-bearing even when the change event does all the saving**: a form
with `phx-change` but no `phx-submit` is treated as external by
LiveView, so Enter in a typed input native-submits and navigates away,
killing the socket. Point it anywhere harmless — a clause that no-ops
on payloads without `_target` works.

  * **Typed inputs** (text, textarea, email, url, rich_text, number,
    date) carry `phx-debounce="blur"`, so the form's change event
    fires on blur/enter — not per keystroke.
  * **Discrete inputs** (boolean toggle, select, radio, checkbox
    group) fire immediately. Booleans pair the checkbox with a hidden
    `"false"` input and checkbox groups a hidden `""`, so the change
    payload always carries the key even when everything is unticked.
    Checkbox groups submit under `name[]` (not the bare `name`), so
    the host reads a **list** at that key — `cast_field/2` normalizes
    it, dropping the hidden `""` entry.
  * **Media references** (image, video) are not form inputs at all:
    they render the current file (thumbnail for images) plus
    Choose/Clear buttons that push the host's `on_pick`/`on_clear`
    events with `phx-value-field={field key}` and any `pick_params`.
    The host opens its media picker (e.g. core's `MediaSelectorModal`)
    and writes the chosen storage file uuid through its own save path.

Cast the change payload with `PhoenixKitEntities.FormBuilder.cast_field/2`
before persisting — it applies the same per-type coercion and
validation the full form pipeline uses.

Nested forms are invalid HTML: this component renders bare controls
precisely so it can live inside whatever form (or none) the host has;
the host is responsible for the form context.

## Example

    <form
      id={"row-#{value.uuid}"}
      phx-change="extras_changed"
      phx-submit="extras_changed"
    >
      <input type="hidden" name="uuid" value={value.uuid} />
      <.field_input
        :for={field <- @entity.fields_definition}
        field={field}
        name={"extras[#{field["key"]}]"}
        value={value.data[field["key"]]}
        size="xs"
        on_pick="pick_extra_media"
        on_clear="clear_extra_media"
        pick_params={%{"uuid" => value.uuid}}
      />
    </form>

# `field_input`

Renders the control for one field definition. See the moduledoc for
the save contract per field-type family.

## Attributes

* `field` (`:map`) (required) - one fields_definition entry (string keys).
* `name` (`:string`) (required) - form input name, e.g. extras[price]. Checkbox groups append `[]`
  (real options and the hidden `""` fallback both submit under
  `name[]`), so the host reads a list at that key.

* `value` (`:any`) - Defaults to `nil`.
* `id` (`:string`) - derived from name when absent. Defaults to `nil`.
* `size` (`:string`) - Defaults to `"sm"`. Must be one of `"xs"`, `"sm"`, or `"md"`.
* `disabled` (`:boolean`) - Defaults to `false`.
* `class` (`:string`) - extra classes merged onto the styled control — for daisyUI modifiers or layout the host owns, e.g. `join-item` when the field sits inside a joined group. Defaults to `nil`.
* `form` (`:string`) - id of the owning <form> when the control renders OUTSIDE it (the
  HTML form attribute) — e.g. table layouts, where a <form> inside
  <tr> gets foster-parented out by the HTML parser. Applied to every
  native control including the hidden fallbacks.

  Defaults to `nil`.
* `on_pick` (`:string`) - event pushed by the image/video Choose button (required for those types). Defaults to `nil`.
* `on_clear` (`:string`) - event pushed by the image/video Clear button (hidden when absent). Defaults to `nil`.
* `pick_params` (`:map`) - extra phx-value-* params on the pick/clear buttons (row identity).
  `"field"` is reserved — the buttons always send the field key under
  it, so a `pick_params` entry named `field` is dropped.

  Defaults to `%{}`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
