# `MishkaGervaz.Form.Templates.Standard`
[🔗](https://github.com/mishka-group/mishka_gervaz/blob/v0.0.2/lib/mishka_gervaz/form/templates/standard.ex#L1)

Default form template for MishkaGervaz.

Implements `MishkaGervaz.Form.Behaviours.Template` and serves as the
out-of-the-box renderer for every `mishka_gervaz form do … end` block.
Custom templates inherit from this module via `use
MishkaGervaz.Form.Behaviours.Template`, which delegates the four
optional callbacks (`render_loading/1`, `render_field/1`,
`render_group/1`, `render_step_indicator/1`) here.

## Layout modes

  * `:standard` — single-page form, fields rendered in their declared
    groups (or flat when no groups are declared).
  * `:wizard`   — multi-step form with a sequential step indicator and
    step-aware submit / next / previous buttons.
  * `:tabs`     — same step structure as `:wizard` but with free
    navigation between tabs.

Mode selection is read from `@state.static.layout_mode`. The render
pipeline (`render/1`) dispatches notices (`render_notices_at/2`),
the form header / footer chrome, the body (`render_groups/1` or
`render_current_step_groups/1`), upload sections, and submit buttons
in a fixed order so notice positioning stays predictable.

## Two-axis composition

  * **Template** (this module) — *where* things go: groups, steps,
    notices, submit area.
  * **UI adapter** (e.g. `MishkaGervaz.UIAdapters.Tailwind`) — *how*
    things look: every concrete element (`field_group`, `alert`,
    `button`, `step_indicator`, …) is dispatched through
    `MishkaGervaz.Helpers.dynamic_component/1`, which forwards to the
    adapter declared on the resource.

## Field-type dispatch

`render_field/1` delegates per-type rendering to modules under
`MishkaGervaz.Form.Types.Field.*` (e.g.
`MishkaGervaz.Form.Types.Field.Hidden`,
`MishkaGervaz.Form.Types.Field.Relation`). Built-in types are wired
through `render_input/4`; custom types implement
`MishkaGervaz.Form.Behaviours.FieldType` and are referenced directly
in the field DSL (`field :foo, MyApp.FieldTypes.Color`).

## Input scoping

`render_input/4` puts `:table_id` — the UI adapter's name for the scope a control belongs to —
on the base assigns of every field, alongside the `:id` taken from the Phoenix form field. The
adapter's searchable controls (`search_select`, `load_more_select`, `multi_select`, `combobox`,
`string_list_input`) build their wrapper id from that scope plus the field name, so two forms on
one page may share a field name without their ids colliding.

`render_string_list_input/4` sets the same scope itself, since it builds its assigns from the
template assigns rather than from that base.

## Upload progress

`render_upload_entries/1` sets its track width with an inline `style="width: N%"` rather than a
Tailwind width class, as does `MishkaGervaz.UIAdapters.Tailwind.upload_progress/1`.

See `MishkaGervaz.Form.Behaviours.Template`,
`MishkaGervaz.Form.Behaviours.FieldType`,
`MishkaGervaz.Behaviours.UIAdapter`,
`MishkaGervaz.Helpers`, and
`MishkaGervaz.Form.Web.UploadHelpers`.

# `render_form_errors`

Draws `state.form_errors`, the messages of a failed save that no field shows, as one `:error`
alert above the submit row. Draws nothing when there are none.

# `render_loading`

The form while its record loads: the UI adapter's spinner over a "Loading…" label, in a box at
least 280px tall, marked `data-role="gervaz-form-loading"`.

---

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