Component Arguments and HTML Attributes

Components become useful building blocks of our app if we make them reusable. When we reuse components efficiently, we can avoid having to recreate parts of our app again and again. If you want to reuse a component in multiple places, you'll need a way to template out parts of it.

Let's start with two similar but not identical avatar components, that represent different users:

<aside>
  <div class="avatar" title="Tomster's avatar">T</div>
</aside>
<aside class="current-user">
  <div class="avatar" title="Zoey's avatar">Z</div>
</aside>

The structure of these components is identical, but they have somewhat different content (the user's first initial) and attributes (the title and class attributes).

You may notice that the is-active class on the received message avatar from the previous chapters is missing here. We'll cover that in the next chapter on Conditional Content.

Arguments

We can create a component that can be used in both situations by templating the parts of the HTML that are different.

<aside>
  <div class="avatar" title={{@title}}>{{@initial}}</div>
</aside>

The syntax {{@initial}} means that the contents inside the <div> tag are dynamic and will be specified by the <Avatar> tag. Likewise, the {{@title}} syntax means that the contents of the title attribute are dynamic and will be specified in the same way. We can now replace the received message avatar by using the <Avatar> tag and providing it with some arguments.

<Avatar @title="Tomster's avatar" @initial="T" />

This code includes the <Avatar> component, which expects two arguments: @title and @initial.

You are probably familiar with HTML attributes, which tell the browser how to draw an HTML element. The syntax @title= is similar, but instead of telling the browser what to do, it's telling your custom tag what to do.

Zoey says...

You might be wondering why Ember uses the `@` syntax for its components instead of normal HTML attribute syntax. We'll learn why in the next section.

HTML Attributes

Let's try to use our <Avatar> component for the sent message avatar.

<Avatar @title="Zoey's avatar" @initial="Z" />

We're really, really close.

<aside class="current-user">
<aside>
  <div class="avatar" title="Zoey's avatar">Z</div>
</aside>

We're just missing the current-user class on the HTML <aside> element. To make that work, we'll specify the HTML attribute class on the <Avatar> tag.

<Avatar
  @title="Zoey's avatar"
  @initial="Z"
  class="current-user"
/>

The avatar component also needs to specify where to put attributes that were specified on the tag.

<aside ...attributes>
  <div class="avatar" title={{@title}}>{{@initial}}</div>
</aside>

The ...attributes syntax determines where the attributes from a tag should appear in the component's template. Any number of attributes can be specified on the avatar component now, and they will all end up on the element that has ...attributes.

Zoey says...

In general, you should place ...attributes after any attributes you specify to give people using your component an opportunity to override your attribute. If ...attributes appears after an attribute, it overrides that attribute. If it appears before an attribute, it does not.

Place ...attributes before your attributes only if you want to disallow tags from overriding your attributes. This is likely to be unusual.

In addition, the class attribute is special, and will be merged with any existing classes on the element rather than overwriting them. This allows you to progressively add CSS classes to your components, and makes them more flexible overall.

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