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,
-
You can nest the input inside the label.
<label> Ask a question about Ember: <Input @type="text" @value={{this.userQuestion}} /> </label>
-
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}} />
-
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