Aurelia: Custom Element vs Compose

When you build an application with Aurelia you divide the application into reusable chunks, each comprised of a view and a view-model. A view is just an HTML template and a view-model is a JavaScript class.

There are several ways to combine views and view-models and render them into your application: custom elements, the compose element, the TemplatingEngine, and the <router-view> to name a few.

A common question that comes up is:

When should I use a custom element and when should I should I use the compose element?

Here are my thoughts on the subject...

Use a custom element whenever possible.

Compose targets dynamic scenarios. If your <compose> element's view and view-model attributes are static (not data-bound) you probably should have used a custom element for the reasons described below.

Portablity: Custom elements are more portable because they have a higher degree of encapsulation. A custom element's template cannot access the outer scope, all data must be passed in via @bindable properties. This contrasts with <compose>, which allows accessing the outer scope, making it very easy to get sloppy and make assumptions about the environment in which a composed view will be used.

Features: Custom elements have more features than the <compose> element. Template parts/slots (transclusion), bindable properties, ability to "globalize" via globalResources and more.

Reuse: It's much easier for a team to reuse a widget when it's encapsulated in a custom element and globalized via globalResources. The team can simply write <mega-widget ...></mega-widget> as opposed to having to remember the relative path to mega-widget.html and mega-widget.js and write a valid <compose view="..." view-model="..."></compose> expression.

Better fit: Any use-case where you are creating a data-entry widget really deserves a custom element. It's far easier to use a currency custom element- eg: <currency value.bind="unitCost"></currency> than it would be to try and achieve similar results with <compose>. Not sure how you would accomplish it really.

CSS: it's easier to target a custom element with css selectors than a specific compose element instance. mega-element { display: block; ... }