Components Forms (v1)

Forms (v1)

This page is for users using the old form structure (pre Phoenix 1.7).

v1 way (pre Phoenix 1.7):

<.form :let={f} as={:user} for={@changeset} phx-submit="on_submit">
  <.form_field type="text_input" form={f} field={:your_field} />

  <.form_field
    form={f}
    field={:a_select_field}
    type="select"
    options={[{"Option 1", "1"}, {"Option 2", "2"}]}
  />

  <.button type="submit" label="Submit" />
</.form>

v2 way (Phoenix 1.7):

<.form for={@form} phx-submit="on_submit">
  <.field field={@form[:email]} />

  <.field
    field={@form[:email]}
    type="select"
    options={[{"Option 1", "1"}, {"Option 2", "2"}]}
  />

  <.button type="submit" label="Submit" />
</.form>

Go here for the v2 docs.

There are two ways of creating form fields
  1. All inclusive option: Use `.form_field', which includes the input label and any errors on the changeset. Use this if you just want a good looking form that works with errors out of the box.
  2. Explicit option: Individually write out the label, input and errors. Do this when you want to be more explicit option on where the label or errors go.
The following code shows both methods for each form element.
Form field
`.form_field` is the easiest way to create input fields. We support every field Phoenix supports plus more.
          <.form :let={f} as={:user} for={@changeset}>
  <.form_field
    type="text_input"
    form={f}
    field={:your_field}
    placeholder="Placeholder"
  />
  <.form_field
    type="select"
    options={[Admin: "admin", User: "user"]}
    form={f}
    field={:select}
  />
  <.form_field type="password_input" form={f} field={:password} />
  <.form_field
    type="radio_group"
    options={[Male: "male", Female: "female", Other: "other"]}
    form={f}
    field={:gender}
  />
  <div class="flex justify-end gap-3">
    <.button type="button" label="Cancel" color="white" />
    <.button type="submit" label="Submit" />
  </div>
</.form>

        
Form Field properties
            # <.form_field>
  attr(:form, :any, doc: "the form object", required: true)
  attr(:field, :atom, doc: "field in changeset / form", required: true)
  attr(:label, :string, doc: "labels your field")
  attr(:label_class, :string, default: nil, doc: "extra CSS for your label")
  attr(:help_text, :string, default: nil, doc: "context/help for your field")

  attr(:type, :string, default: "text_input", values: [
    "text_input",
    "email_input",
    "number_input",
    "password_input",
    "search_input",
    "telephone_input",
    "url_input",
    "time_input",
    "time_select",
    "date_input",
    "date_select",
    "datetime_local_input",
    "datetime_select",
    "color_input",
    "file_input",
    "range_input",
    "textarea",
    "select",
    "checkbox",
    "checkbox_group",
    "radio_group",
    "switch",
    "hidden_input"],
  doc: "The type of input")

attr(:wrapper_classes, :string, default: "pc-form-field-wrapper", doc: "CSS class for wrapper")
attr :rest, :global, include: @form_attrs

        
Text input
          <!-- Explicit option  -->
<.form_label form={f} field={:your_field} />
<.text_input form={f} field={:your_field} placeholder="eg. John" />
<.form_field_error form={f} field={:your_field} class="mt-1" />

<!-- All inclusive option  -->
<.form_field
  type="text_input"
  form={f}
  field={:your_field}
  placeholder="Placeholder"
/>

        

Properties

All properties are forwarded to Phoenix.HTML.Form.html#text_input/3 as opts.
Email input
          <!-- Explicit option  -->
<.form_label form={f} field={:your_field} />
<.email_input form={f} field={:your_field} />
<.form_field_error form={f} field={:your_field} class="mt-1" />

<!-- All inclusive option  -->
<.form_field type="email_input" form={f} field={:your_field} />

        

Properties

All properties are forwarded to Phoenix.HTML.Form.html#text_input/3 as opts.
Number input
          <!-- Explicit option  -->
<.form_label form={f} field={:your_field} />
<.number_input form={f} field={:your_field} placeholder="eg. 1" />
<.form_field_error form={f} field={:your_field} class="mt-1" />

<!-- All inclusive option  -->
<.form_field type="number_input" form={f} field={:your_field} />

        

Properties

All properties are forwarded to Phoenix.HTML.Form.html#text_input/3 as opts.
Password input
          <!-- Explicit option  -->
<.form_label form={f} field={:your_field} />
<.password_input form={f} field={:your_field} />
<.form_field_error form={f} field={:your_field} class="mt-1" />

<!-- All inclusive option  -->
<.form_field type="password_input" form={f} field={:your_field} />

        

Properties

All properties are forwarded to Phoenix.HTML.Form.html#text_input/3 as opts.
Search input
          <!-- Explicit option  -->
<.form_label form={f} field={:your_field} />
<.search_input form={f} field={:your_field} />
<.form_field_error form={f} field={:your_field} class="mt-1" />

<!-- All inclusive option  -->
<.form_field type="search_input" form={f} field={:your_field} />

        

Properties

All properties are forwarded to Phoenix.HTML.Form.html#text_input/3 as opts.
Telephone input
          <!-- Explicit option  -->
<.form_label form={f} field={:your_field} />
<.telephone_input form={f} field={:your_field} />
<.form_field_error form={f} field={:your_field} class="mt-1" />

<!-- All inclusive option  -->
<.form_field type="telephone_input" form={f} field={:your_field} />

        

Properties

All properties are forwarded to Phoenix.HTML.Form.html#text_input/3 as opts.
URL input
          <!-- Explicit option  -->
<.form_label form={f} field={:your_field} />
<.url_input form={f} field={:your_field} />
<.form_field_error form={f} field={:your_field} class="mt-1" />

<!-- All inclusive option  -->
<.form_field type="url_input" form={f} field={:your_field} />

        

Properties

All properties are forwarded to Phoenix.HTML.Form.html#text_input/3 as opts.
Hidden input
          <!-- Explicit option  -->
<.hidden_input form={f} field={:your_field} />

<!-- All inclusive option  -->
<.form_field type="hidden_input" form={f} field={:your_field} />

        

Properties

All properties are forwarded to Phoenix.HTML.Form.html#text_input/3 as opts.
Time input
          <!-- Explicit option  -->
<.form_label form={f} field={:your_field} />
<.time_input form={f} field={:your_field} />
<.form_field_error form={f} field={:your_field} class="mt-1" />

<!-- All inclusive option  -->
<.form_field type="time_input" form={f} field={:your_field} />

        

Properties

All properties are forwarded to Phoenix.HTML.Form.html#text_input/3 as opts.
Time select
:
          <!-- Explicit option  -->
<.form_label form={f} field={:your_field} />
<.time_select form={f} field={:your_field} />
<.form_field_error form={f} field={:your_field} class="mt-1" />

<!-- All inclusive option  -->
<.form_field type="time_select" form={f} field={:your_field} />

        

Properties

All properties are forwarded to Phoenix.HTML.Form.html#time_select/3 as opts.
Date input
          <!-- Explicit option  -->
<.form_label form={f} field={:your_field} />
<.date_input form={f} field={:your_field} />
<.form_field_error form={f} field={:your_field} class="mt-1" />

<!-- All inclusive option  -->
<.form_field type="date_input" form={f} field={:your_field} />

        

Properties

All properties are forwarded to Phoenix.HTML.Form.html#text_input/3 as opts.
Date select
/ /
          <!-- Explicit option  -->
<.form_label form={f} field={:your_field} />
<.date_select form={f} field={:your_field} />
<.form_field_error form={f} field={:your_field} class="mt-1" />

<!-- All inclusive option  -->
<.form_field type="date_select" form={f} field={:your_field} />

        

Properties

All properties are forwarded to Phoenix.HTML.Form.html#time_select/3 as opts.
Datetime local input
          <!-- Explicit option  -->
<.form_label form={f} field={:your_field} />
<.datetime_local_input form={f} field={:your_field} />
<.form_field_error form={f} field={:your_field} class="mt-1" />

<!-- All inclusive option  -->
<.form_field type="datetime_local_input" form={f} field={:your_field} />

        

Properties

All properties are forwarded to Phoenix.HTML.Form.html#datetime_local_input/3 as opts.
Datetime select
/ / :
          <!-- Explicit option  -->
<.form_label form={f} field={:your_field} />
<.datetime_select form={f} field={:your_field} />
<.form_field_error form={f} field={:your_field} class="mt-1" />

<!-- All inclusive option  -->
<.form_field type="datetime_select" form={f} field={:your_field} />

        

Properties

All properties are forwarded to Phoenix.HTML.Form.html#datetime_select/3 as opts.
Color input
          <!-- Explicit option  -->
<.form_label form={f} field={:your_field} />
<.search_input form={f} field={:your_field} />
<.form_field_error form={f} field={:your_field} class="mt-1" />

<!-- All inclusive option  -->
<.form_field type="color_input" form={f} field={:your_field} />

        

Properties

All properties are forwarded to Phoenix.HTML.Form.html#color_input/3 as opts.
File input
          <!-- Explicit option  -->
<.form_label form={f} field={:your_field} />
<.file_input form={f} field={:your_field} />
<.form_field_error form={f} field={:your_field} class="mt-1" />

<!-- All inclusive option  -->
<.form_field type="file_input" form={f} field={:your_field} />

        

Properties

All properties are forwarded to Phoenix.HTML.Form.html#file_input/3 as opts.
Range input
          <!-- Explicit option  -->
<.form_label form={f} field={:your_field} />
<.range_input form={f} field={:your_field} />
<.form_field_error form={f} field={:your_field} class="mt-1" />

<!-- All inclusive option  -->
<.form_field type="range_input" form={f} field={:your_field} />

        

Properties

All properties are forwarded to Phoenix.HTML.Form.html#range_input/3 as opts.
Textarea
          <!-- Explicit option  -->
<.form_label form={f} field={:your_field} />
<.textarea form={f} field={:your_field} />
<.form_field_error form={f} field={:your_field} class="mt-1" />

<!-- All inclusive option  -->
<.form_field type="textarea" form={f} field={:your_field} />

        

Properties

All properties are forwarded to Phoenix.HTML.Form.html#textarea/3 as opts.
Select
          <!-- Explicit option  -->
<.form_label form={f} field={:your_field} />
<.select
  options={["Admin": "admin", "User": "user"]}
  form={f}
  field={:your_field}
/>
<.form_field_error form={f} field={:your_field} class="mt-1" />

<!-- All inclusive option  -->
<.form_field
  type="select"
  options={["Admin": "admin", "User": "user"]}
  form={f}
  field={:your_field}
/>

        

Properties

All properties are forwarded to Phoenix.HTML.Form.html#select/4 as opts.
Multiple select

We are yet to implement the HTML5 multiple select due to it being hard to use for end users. Instead we recommend using our checkbox group component.

Switch
          <!-- Explicit option  -->
<.switch form={f} field={:your_field} />
<.form_field_error form={f} field={:your_field} class="mt-1" />

<!-- All inclusive option  -->
<.form_field type="switch" form={f} field={:your_field} label="I agree" />

        

Properties

All properties are forwarded to Phoenix.HTML.Form.html#checkbox/3 as opts.
Checkbox
          <!-- Explicit option  -->
<.checkbox form={f} field={:your_field} />
<.form_field_error form={f} field={:your_field} class="mt-1" />

<!-- All inclusive option  -->
<.form_field type="checkbox" form={f} field={:your_field} label="I accept" />

        

Properties

All properties are forwarded to Phoenix.HTML.Form.html#checkbox/3 as opts.
Checkbox group

Use this instead of a multiple select (when the field data type is a list).

          <.form_field
  type="checkbox_group"
  form={f}
  field={:your_field}
  label="Column layout"
  options={[
    {"Option 1", "option_1"},
    {"Option 2", "option_2"},
    {"Option 3", "option_3"},
    {"Option 4", "option_4"}
  ]}
/>

<.form_field
  type="checkbox_group"
  form={f}
  layout={:row}
  field={:your_field}
  label="Row layout"
  options={[
    {"Option 1", "option_1"},
    {"Option 2", "option_2"},
    {"Option 3", "option_3"},
    {"Option 4", "option_4"}
  ]}
/>

        
Properties
            attr(:form, :any, default: nil, doc: "")
  attr(:field, :atom, default: nil, doc: "")
  attr(:label, :string, default: nil, doc: "labels your field")
  attr(:class, :string, default: "", doc: "extra classes for the text input")
  attr(:options, :list, default: [], doc: "options for the select")
  attr(:layout, :atom, default: :col, values: [:row, :col], doc: "layout for the checkboxes")
  attr(:checked, :list, doc: "a list of checked values")
  attr(:rest, :global, include: @form_attrs)

        
Radio
          <!-- Explicit option  -->
<.form_label form={f} field={:your_field} />

<div class="flex flex-col gap-1">
  <label class="inline-flex items-center gap-3 text-sm text-gray-900 dark:text-gray-200">
    <.radio form={f} field={:your_field} value="green" />
    <div>Green</div>
  </label>

  <label class="inline-flex items-center gap-3 text-sm text-gray-900 dark:text-gray-200">
    <.radio form={f} field={:your_field} value="blue" />
    <div>Blue</div>
  </label>

  <label class="inline-flex items-center gap-3 text-sm text-gray-900 dark:text-gray-200">
    <.radio form={f} field={:your_field} value="gray" />
    <div>Gray</div>
  </label>
</div>

<.form_field_error form={f} field={:your_field} class="mt-1" />

<!-- All inclusive option  -->
<.form_field
  type="radio_group"
  form={f}
  field={:radio}
  options={["Option 1": "option_1", "Option 2": "option_2", "Option 3": "option_3"]}
  label="Column layout"
/>

<.form_field
  type="radio_group"
  form={f}
  field={:radio_group}
  layout={:row}
  label="Row layout"
  options={[
    "Option 1": "option_1",
    "Option 2": "option_2",
    "Option 3": "option_3"
  ]}
/>

        

Properties

All properties are forwarded to Phoenix.HTML.Form.html#radio_button/4 as opts.
Form label

Usually paired with inputs.

          <.form_label form={f} field={:email} />
<.form_label form={f} field={:email} label="Custom label" />

        

Properties

All properties are forwarded to Phoenix.HTML.Form.html#label/3 as opts.
Form field error

Will display any errors in your changeset for a particular field.

          <.form_field_error form={f} field={:your_field} />

        
Help text

You can add additional instructions at the bottom of any input.

Type your email above
          <.form_label form={f} field={:email} />
<.text_input form={f} field={:email} />
<.form_help_text class="mt-2">Type your email above</.form_help_text>

OR

<.form_field
  type="text_input"
  form={f}
  field={:email}
  help_text="Type your email above"
/>