home
  • Blog
3.8
  • Getting Started
  • Tutorial
  • The Object Model
  • Templating
  • Components
    • Defining a Component
    • The Component Lifecycle
    • Passing Properties to a Component
    • Wrapping Content in a Component
    • Customizing a Component's Element
    • Using Block Params
    • Handling Events
    • Triggering Changes with Actions
  • Controllers
  • Routing
  • Ember Data
  • Addons and Dependencies
  • Testing
  • Configuration
  • Application Concerns
  • Ember Inspector
  • Contributing to Ember.js
  • Glossary
  • Reference
Old Guides - You are viewing the guides for Ember v3.8.0.
Go to v5.0.0

Defining a Component

Edit pencil

To define a component, run:

ember generate component my-component-name

Ember components are used to turn markup text and styles into reusable content. Components consist of two parts: a JavaScript component file that defines behavior, and its accompanying Handlebars template that defines the markup for the component's UI.

A sample component template could look like this:

app/templates/components/blog-post.hbs
<article class="blog-post">
  <h1>{{this.title}}</h1>
  <p>{{yield}}</p>
  <p>Edit title: {{input type="text" value=this.title}}</p>
</article>

Given the above template, you can now use the <BlogPost /> component:

app/templates/index.hbs
{{#each this.model as |post|}}
  <BlogPost @title={{post.title}}>
    {{post.body}}
  </BlogPost>
{{/each}}
Zoey says...
In Ember templates there are different ways to invoke a Component. The syntax above is referred to as angle bracket invocation syntax, and it might not look familiar if you are looking at older code samples that use the classic invocation syntax. For more examples of ways to use Components in a template, see the Syntax Conversion Guide, a previous version of the Guides or Ember.js API documentation.

Its model is populated in model hook in the route handler:

app/routes/index.js
import Route from '@ember/routing/route';

export default Route.extend({
  model() {
    return this.store.findAll('post');
  }
});

Each component is backed by an element under the hood. By default, Ember will use a <div> element to contain your component's template. To learn how to change the element Ember uses for your component, see Customizing a Component's Element.

Defining a Component Subclass

Often times, your components will contain reused Handlebar templates. In those cases, you do not need to write any JavaScript at all. Handlebars allows you to define templates and reuse them as components.

If you need to customize the behavior of the component you'll need to define a subclass of Component. For example, you would need a custom subclass if you wanted to change a component's element, respond to actions from the component's template, or manually make changes to the component's element using JavaScript.

Ember knows which subclass powers a component based on its filename. For example, if you have a component called blog-post, you would create a file at app/components/blog-post.js. If your component was called audio-player-controls, the file name would be at app/components/audio-player-controls.js.

Dynamically rendering a component

The {{component}} helper can be used to defer the selection of a component to run time. The <MyComponent /> syntax always renders the same component, while using the {{component}} helper allows choosing a component to render on the fly. This is useful in cases where you want to interact with different external libraries depending on the data. Using the {{component}} helper would allow you to keep different logic well separated.

The first parameter of the helper is the name of a component to render, as a string. So {{component 'blog-post'}} is the same as using <BlogPost />.

The real value of {{component}} comes from being able to dynamically pick the component being rendered. Below is an example of using the helper as a means of choosing different components for displaying different kinds of posts:

app/templates/components/foo-component.hbs
<h3>Hello from foo!</h3>
<p>{{this.post.body}}</p>
app/templates/components/bar-component.hbs
<h3>Hello from bar!</h3>
<div>{{this.post.author}}</div>
app/routes/index.js
import Route from '@ember/routing/route';

export default Route.extend({
  model() {
    return this.store.findAll('post');
  }
});
app/templates/index.hbs
{{#each this.model as |post|}}
  {{!-- either foo-component or bar-component --}}
  {{component post.componentName post=post}}
{{/each}}

or

app/templates/index.hbs
{{#each this.model as |post|}}
  {{!-- either foo-component or bar-component --}}
  {{#let (component this.componentName) as |Post|}}
    <Post @post={{post}} />
  {{/let}}
{{/each}}

When the parameter passed to {{component}} evaluates to null or undefined, the helper renders nothing. When the parameter changes, the currently rendered component is destroyed and the new component is created and brought in.

Picking different components to render in response to the data allows you to have different template and behavior for each case. The {{component}} helper is a powerful tool for improving code modularity.

left arrow
Writing Helpers
The Component Lifecycle
right arrow
On this page

  • Defining a Component Subclass
  • Dynamically rendering a component
Team Sponsors Security Legal Branding Community Guidelines
Twitter GitHub Discord Mastodon

If you want help you can contact us by email, open an issue, or get realtime help by joining the Ember Discord.

© Copyright 2023 - Tilde Inc.
Ember.js is free, open source and always will be.


Ember is generously supported by
blue