Built-in Components

Out of the box, Ember provides 2 components for building a form:

These components are similar in HTML markup to the native <input> or <textarea> elements. In contrast to the native elements, <Input> and <Textarea> automatically update the state of their bound values.

<Input>

We mentioned that the built-in components are similar in HTML markup to their native counterparts. What does this mean?

Consider the following example in a template file.

<label for="user-question">Ask a question about Ember:</label>
<Input
  @id="user-question"
  @type="text"
  @value="How do text fields work?"
/>

When Ember renders this template, you will see the following HTML code:

<label for="user-question">Ask a question about Ember:</label>
<input id="user-question" type="text" value="How do text fields work?" />

Ways to associate labels and inputs

Every input should be associated with a label. In HTML, there are a few ways to do this. With the built-in <Input> component,

  1. You can nest the input inside the label.

    <label>
     Ask a question about Ember:
    
     <Input
       @type="text"
       @value={{this.userQuestion}}
     />
    </label>
    
  2. You can create an ID (globally unique within the webpage), then associate the label to the input with for attribute and @id argument.

    <label for={{this.myUniqueId}}>
     Ask a question about Ember:
    </label>
    
    <Input
     @id={{this.myUniqueId}}
     @type="text"
     @value={{this.userQuestion}}
    />
    
  3. You can use the aria-label attribute to label the input with a string that is visually hidden but still available to assistive technology.

    <Input
     aria-label="Ask a question about Ember"
     @type="text"
     @value={{this.userQuestion}}
    />
    

While it is more appropriate to use the <label> element, the aria-label attribute can be used in instances where visible text content is not possible.

Setting attributes on <Input>

With a few exceptions, you can pass input attributes as attributes (i.e. do not prepend @) to the <Input> component.

For example, the aria-labelledby attribute may be useful if you have a search input. The search button can serve as the label for the input element:

<Input aria-labelledby="button-search" />
<button id="button-search" type="button">Search</button>

If an attribute is set to a quoted string ("button-search" in the prior example), its value will be set directly on the element.

You can also bind the attribute value to a property that you own. In the next example, the disabled attribute is bound to the value of isReadOnly in the current context.

<label for="input-name">Name:</label>
<Input
  @id="input-name"
  @value={{this.name}}
  disabled={{this.isReadOnly}}
  maxlength="50"
/>

Recall that there were a few exceptions. The following input attributes must be passed as arguments (i.e. do prepend @) to the <Input> component:

  • @checked
  • @id
  • @type
  • @value

Actions

Starting with Ember Octane, we recommend using the {{on}} modifier to call an action on specific events such as the input event.

<label for="input-name">Name:</label>
<Input
  @id="input-name"
  @value={{this.name}}
  {{on "input" this.validateName}}
/>

The event name (e.g. "focusout", "input", "keydown") always follows the casing that the HTML standard uses.

For backwards compatibility with earlier versions of Ember, it is possible to call an action by passing an event argument.

<label for="input-name">Name:</label>
<Input
  @id="input-name"
  @value={{this.name}}
  @input={{this.validateName}}
/>

The argument name is always dasherized (e.g. @focus-out, @input, @key-down). To minimize confusion, we recommend that you use the {{on}} modifier. (Learn more about the {{on}} modifier.)

Lastly, Ember also provides custom input events @enter and @escape-press. These events do not exist on native input elements, but you may find them to be useful for handling keyboard interactions.

The modern, Octane-style way to handle keyboard events is to write a modifier to separate concerns: The component manages the state, while the modifier manages interactions with the DOM. Your action will receive an actual event object.

There are community-made addons to help manage keyboard events. For example, with ember-keyboard, you can write,

{{!-- Before --}}
<Input
  @enter={{this.doSomething}}
  @escape-press={{this.doSomethingElse}}
/>

{{!-- After --}}
<Input
  {{on-key "Enter" this.doSomething}}
  {{on-key "Escape" this.doSomethingElse event="keydown"}}
/>

Note, the keydown event was used for Escape because keypress is deprecated.

Checkboxes

You can use the <Input> component to create a checkbox. Set @type to the string "checkbox", and use @checked instead of @value.

<label for="admin-checkbox">Is Admin?</label>
<Input
  @id="admin-checkbox"
  @type="checkbox"
  @checked={{this.isAdmin}}
/>

To call an action on specific events, use the {{on}} modifier:

<label for="admin-checkbox">Is Admin?</label>
<Input
  @id="admin-checkbox"
  @type="checkbox"
  @checked={{this.isAdmin}}
  {{on "input" this.validateRole}}
/>

<Textarea>

The following example shows how to bind this.userComment to a text area's value.

<label for="user-comment">Comment:</label>
<Textarea
  @id="user-comment"
  @value={{this.userComment}}
  rows="6"
  cols="80"
/>

Setting attributes on <Textarea>

With the exception of @value argument, you can use any attribute that <textarea> natively supports.

Binding dynamic attribute

You might need to bind a property dynamically to an input if you're building a flexible form, for example. To achieve this you need to use the {{get}} and {{mut}} in conjunction like shown in the following example:

<label for="input-name">Name:</label>
<Input
  @id="input-name"
  @value={{mut (get this.person this.field)}}
/>

The {{get}} helper allows you to dynamically specify which property to bind, while the {{mut}} helper allows the binding to be updated from the input. See the respective helper documentation for more detail: {{get}} and {{mut}}.

© 2020 Yehuda Katz, Tom Dale and Ember.js contributors
Licensed under the MIT License.
https://guides.emberjs.com/v3.25.0/components/built-in-components