Field

Renders a form field including input, label, errors, and description.

Read more Read less

A Phoenix.HTML.FormField may be passed as argument, which is used to retrieve the input name, ID, and values. Otherwise all attributes may be passed explicitly.

Usage

Types

In addition to all HTML input types, the following type values are also supported:

  • "select"
  • "checkbox-group"
  • "radio-group"
  • "switch"

Class and Global Attribute

Note that the class attribute is applied to the outer container, while the rest global attribute is applied to the <input> element.

Gettext

To translate field errors as well as the required_text and optional_text using Gettext, set the gettext_module option when building the component:

build_field(gettext_module: MyApp.Gettext)

Label positioning

The component does not provide an attribute to modify label positioning directly. Instead, label positioning should be handled with CSS. If your application requires different label positions, such as horizontal and vertical layouts, it is recommended to add a modifier class to the form.

For example, the default style could position labels above inputs. To place labels to the left of the inputs in a horizontal form layout, you can add an is-horizontal class to the form:

<.form class="is-horizontal">
<!-- inputs -->

</.form>

Then, in your CSS, apply the necessary styles to the .field class within forms having the is-horizontal class:

form.is-horizontal .field {
  // styles to position label left of the input
}

The component has a hide_label attribute to visually hide labels while still making them accessible to screen readers. If all labels within a form need to be visually hidden, it may be more convenient to define a .has-visually-hidden-labels modifier class for the <form>.

<.form class="has-visually-hidden-labels">
<!-- inputs -->

</.form>

Ensure to take checkbox and radio labels into consideration when writing the CSS styles.

Examples

<.field field={@form[:name]} />
<.field field={@form[:email]} type="email" />

Radio group and checkbox group

The radio-group and checkbox-group types allow you to easily render groups of radio buttons or checkboxes with a single component invocation. The options attribute is required for these types and has the same format as the options for the select type, except that options may not be nested.

<.field
  field={@form[:email]}
  type="checkbox-group"
  label="Cuisine"
  options={[
    {"Mexican", "mexican"},
    {"Japanese", "japanese"},
    {"Libanese", "libanese"}
  ]}
/>

Note that the checkbox-group type renders an additional hidden input with an empty value before the checkboxes. This ensures that a value exists in case all checkboxes are unchecked. Consequently, the resulting list value includes an extra empty string. While Ecto.Changeset.cast/3 filters out empty strings in array fields by default, you may need to handle the additional empty string manual in other contexts.

Radio group
Checkbox group
<Phoenix.Component.form for={%{}} as={:story} :let={f}>
  <.field
    field={f[:field]}
    id="field-basic-inputs-text"
    label="Text"
    type="text"
    placeholder="Some text"
  />
  <.field
    field={f[:field]}
    id="field-basic-inputs-email"
    label="E-mail"
    type="email"
    placeholder="email@example.com"
  />
  <.field
    field={f[:field]}
    id="field-basic-inputs-password"
    label="Password"
    type="password"
    placeholder="12345678"
  />
  <.field
    field={f[:field]}
    id="field-basic-inputs-number"
    label="Number"
    type="number"
    placeholder="250"
  />
  <.field
    field={f[:field]}
    id="field-basic-inputs-search"
    label="Search"
    type="search"
    placeholder="Search term"
  />
  <.field
    field={f[:field]}
    id="field-basic-inputs-tel"
    label="Phone number"
    type="tel"
    placeholder="+818012345678"
  />
  <.field
    field={f[:field]}
    id="field-basic-inputs-url"
    label="URL"
    type="url"
    placeholder="https://www.msf.org"
  />
  <.field
    field={f[:field]}
    id="field-basic-inputs-textarea"
    label="Textarea"
    type="textarea"
    rows="5"
    placeholder="Some text"
  />
  <.field
    field={f[:field]}
    id="field-basic-inputs-range"
    label="Range"
    max="100"
    min="0"
    type="range"
    step="10"
  />
  <.field field={f[:field]} id="field-basic-inputs-color" label="Color" type="color"/>
  <.field field={f[:field]} id="field-basic-inputs-date" label="Date" type="date"/>
  <.field field={f[:field]} id="field-basic-inputs-time" label="Time" type="time"/>
  <.field
    field={f[:field]}
    id="field-basic-inputs-datetime-local"
    label="Datetime local"
    type="datetime-local"
  />
  <.field field={f[:field]} id="field-basic-inputs-week" label="Week" type="week"/>
  <.field
    field={f[:field]}
    id="field-basic-inputs-select"
    label="Select"
    type="select"
    options={["Option 1", "Option 2", "Option 3"]}
  />
  <.field
    field={f[:field]}
    id="field-basic-inputs-multiple-select"
    label="Multiple select"
    type="select"
    options={["Option 1", "Option 2", "Option 3"]}
    multiple
  />
  <.field
    field={f[:field]}
    id="field-basic-inputs-radio-group"
    label="Radio group"
    type="radio-group"
    options={["Option 1", "Option 2", "Option 3"]}
  />
  <.field
    field={f[:field]}
    id="field-basic-inputs-checkbox"
    label="Checkbox"
    type="checkbox"
  />
  <.field field={f[:field]} id="field-basic-inputs-switch" label="Switch" type="switch"/>
  <.field
    field={f[:field]}
    id="field-basic-inputs-checkbox-group"
    label="Checkbox group"
    type="checkbox-group"
    options={["Option 1", "Option 2", "Option 3"]}
  />
</Phoenix.Component.form>
Radio group
Checkbox group
<Phoenix.Component.form for={%{}} as={:story} :let={f}>
  <.field
    field={f[:field]}
    id="field-required-inputs-text"
    label="Text"
    type="text"
    placeholder="Some text"
    validations={[required: true]}
  />
  <.field
    field={f[:field]}
    id="field-required-inputs-select"
    label="Select"
    type="select"
    options={["Option 1", "Option 2", "Option 3"]}
    validations={[required: true]}
  />
  <.field
    field={f[:field]}
    id="field-required-inputs-radio-group"
    label="Radio group"
    type="radio-group"
    options={["Option 1", "Option 2", "Option 3"]}
    validations={[required: true]}
  />
  <.field
    field={f[:field]}
    id="field-required-inputs-checkbox"
    label="Checkbox"
    type="checkbox"
    validations={[required: true]}
  />
  <.field
    field={f[:field]}
    id="field-required-inputs-switch"
    label="Switch"
    type="switch"
    validations={[required: true]}
  />
  <.field
    field={f[:field]}
    id="field-required-inputs-checkbox-group"
    label="Checkbox group"
    type="checkbox-group"
    options={["Option 1", "Option 2", "Option 3"]}
    validations={[required: true]}
  />
</Phoenix.Component.form>
<Phoenix.Component.form for={%{}} as={:story} :let={f}>
  <.field
    field={f[:field]}
    id="field-description-and-errors-only-values"
    label="Dog breed"
    type="text"
    options={["Labrador Retriever", "German Shepherd", "Golden Retriever", "Bulldog", "Beagle", "Poodle", "Rottweiler", "Yorkshire Terrier", "Boxer", "Dachshund"]}
    placeholder="Beagle"
  />
  <.field
    field={f[:field]}
    id="field-description-and-errors-labels-and-values"
    label="Dog breed"
    type="text"
    options={[{"Labrador Retriever", "labrador_retriever"}, {"German Shepherd", "german_shepherd"}, {"Golden Retriever", "golden_retriever"}, {"Bulldog", "bulldog"}, {"Beagle", "beagle"}, {"Poodle", "poodle"}, {"Rottweiler", "rottweiler"}, {"Yorkshire Terrier", "yorkshire_terrier"}, {"Boxer", "boxer"}, {"Dachshund", "dachshund"}]}
    placeholder="Poodle"
  />
</Phoenix.Component.form>
Tell us about yourself.
  • too many characters
  • too boring
Tell us about yourself.
  • too many characters
<Phoenix.Component.form for={%{}} as={:story} :let={f}>
  <.field
    field={f[:field]}
    id="field-description-and-errors-description"
    label="With description"
    type="text"
    placeholder="Some text"
  >
    <:description>Tell us about yourself.</:description>
  </.field>
  <.field
    field={f[:field]}
    id="field-description-and-errors-errors"
    label="Text"
    type="text"
    errors={["too many characters", "too boring"]}
    placeholder="With errors"
  />
  <.field
    field={f[:field]}
    id="field-description-and-errors-description-and-errors"
    label="With description and errors"
    type="text"
    errors={["too many characters"]}
    placeholder="Some text"
  >
    <:addon_left>Tell us about yourself.</:addon_left>
  </.field>
</Phoenix.Component.form>
<Phoenix.Component.form for={%{}} as={:story} :let={f}>
  <.field
    field={f[:field]}
    id="field-addons-addon-left"
    label="Left"
    type="text"
    placeholder="Some text"
  >
    <:addon_left>
      <.icon><svg
      xmlns="http://www.w3.org/2000/svg"
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
      stroke-linecap="round"
      stroke-linejoin="round"
      class="lucide lucide-mail"
    >
      <rect width="20" height="16" x="2" y="4" rx="2" /><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" />
    </svg>
    </.icon>
    </:addon_left>
  </.field>
  <.field
    field={f[:field]}
    id="field-addons-addon-right"
    label="Right"
    type="text"
    placeholder="Some text"
  >
    <:addon_right>
      <.icon><svg
      xmlns="http://www.w3.org/2000/svg"
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
      stroke-linecap="round"
      stroke-linejoin="round"
      class="lucide lucide-mail"
    >
      <rect width="20" height="16" x="2" y="4" rx="2" /><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" />
    </svg>
    </.icon>
    </:addon_right>
  </.field>
  <.field
    field={f[:field]}
    id="field-addons-addon-left-and-right"
    label="Left and right"
    type="text"
    placeholder="Some text"
  >
    <:addon_left>
      <.icon><svg
      xmlns="http://www.w3.org/2000/svg"
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
      stroke-linecap="round"
      stroke-linejoin="round"
      class="lucide lucide-mail"
    >
      <rect width="20" height="16" x="2" y="4" rx="2" /><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" />
    </svg>
    </.icon>
    </:addon_left>
    <:addon_right>
      <.icon><svg
      xmlns="http://www.w3.org/2000/svg"
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
      stroke-linecap="round"
      stroke-linejoin="round"
      class="lucide lucide-check"
    >
      <path d="M20 6 9 17l-5-5" />
    </svg>
    </.icon>
    </:addon_right>
  </.field>
</Phoenix.Component.form>