LogoLogo
HomeDiscourseBlogDiscord
  • Introduction
  • Introduction
    • Quick start
    • Aurelia for new developers
    • Hello world
      • Creating your first app
      • Your first component - part 1: the view model
      • Your first component - part 2: the view
      • Running our app
      • Next steps
  • Templates
    • Template Syntax
      • Attribute binding
      • Event binding
      • Text interpolation
      • Template promises
      • Template references
      • Template variables
      • Globals
    • Custom attributes
    • Value converters (pipes)
    • Binding behaviors
    • Form Inputs
    • CSS classes and styling
    • Conditional Rendering
    • List Rendering
    • Lambda Expressions
    • Local templates (inline templates)
    • SVG
  • Components
    • Component basics
    • Component lifecycles
    • Bindable properties
    • Styling components
    • Slotted content
    • Scope and context
    • CustomElement API
    • Template compilation
      • processContent
      • Extending templating syntax
      • Modifying template parsing with AttributePattern
      • Extending binding language
      • Using the template compiler
      • Attribute mapping
  • Getting to know Aurelia
    • Routing
      • @aurelia/router
        • Getting Started
        • Creating Routes
        • Routing Lifecycle
        • Viewports
        • Navigating
        • Route hooks
        • Router animation
        • Route Events
        • Router Tutorial
        • Router Recipes
      • @aurelia/router-lite
        • Getting started
        • Router configuration
        • Configuring routes
        • Viewports
        • Navigating
        • Lifecycle hooks
        • Router hooks
        • Router events
        • Navigation model
        • Current route
        • Transition plan
    • App configuration and startup
    • Enhance
    • Template controllers
    • Understanding synchronous binding
    • Dynamic composition
    • Portalling elements
    • Observation
      • Observing property changes with @observable
      • Effect observation
      • HTML observation
      • Using observerLocator
    • Watching data
    • Dependency injection (DI)
    • App Tasks
    • Task Queue
    • Event Aggregator
  • Developer Guides
    • Animation
    • Testing
      • Overview
      • Testing attributes
      • Testing components
      • Testing value converters
      • Working with the fluent API
      • Stubs, mocks & spies
    • Logging
    • Building plugins
    • Web Components
    • UI virtualization
    • Errors
      • Kernel Errors
      • Template Compiler Errors
      • Dialog Errors
      • Runtime HTML Errors
    • Bundlers
    • Recipes
      • Apollo GraphQL integration
      • Auth0 integration
      • Containerizing Aurelia apps with Docker
      • Cordova/Phonegap integration
      • CSS-in-JS with Emotion
      • DOM style injection
      • Firebase integration
      • Markdown integration
      • Multi root
      • Progress Web Apps (PWA's)
      • Securing an app
      • SignalR integration
      • Strongly-typed templates
      • TailwindCSS integration
      • WebSockets Integration
      • Web Workers Integration
    • Playground
      • Binding & Templating
      • Custom Attributes
        • Binding to Element Size
      • Integration
        • Microsoft FAST
        • Ionic
    • Migrating to Aurelia 2
      • For plugin authors
      • Side-by-side comparison
    • Cheat Sheet
  • Aurelia Packages
    • Validation
      • Validation Tutorial
      • Plugin Configuration
      • Defining & Customizing Rules
      • Architecture
      • Tagging Rules
      • Model Based Validation
      • Validation Controller
      • Validate Binding Behavior
      • Displaying Errors
      • I18n Internationalization
      • Migration Guide & Breaking Changes
    • i18n Internationalization
    • Fetch Client
      • Overview
      • Setup and Configuration
      • Response types
      • Working with forms
      • Intercepting responses & requests
      • Advanced
    • Event Aggregator
    • State
    • Store
      • Configuration and Setup
      • Middleware
    • Dialog
  • Tutorials
    • Building a ChatGPT inspired app
    • Building a realtime cryptocurrency price tracker
    • Building a todo application
    • Building a weather application
    • Building a widget-based dashboard
    • React inside Aurelia
    • Svelte inside Aurelia
    • Synthetic view
    • Vue inside Aurelia
  • Community Contribution
    • Joining the community
    • Code of conduct
    • Contributor guide
    • Building and testing aurelia
    • Writing documentation
    • Translating documentation
Powered by GitBook
On this page
  • Creating Components
  • Explicit Component Creation with @customElement
  • Configuring the @customElement Decorator
  • Programmatic Component Creation
  • Components declaration with static property $au
  • HTML-Only Components
  • HTML Components with Bindable Properties
  • Components Without Views
  • Registering Your Components
  • Globally Registering a Component
  • Importing a Component Within a Template
  • Containerless Components
  • Using the @customElement Decorator
  • The @containerless Decorator
  • Containerless Elements in Views

Was this helpful?

Export as PDF
  1. Components

Component basics

Components are the building blocks of Aurelia applications. This guide covers the essentials of creating, configuring, and using components, complete with practical code examples.

PreviousSVGNextComponent lifecycles

Last updated 1 year ago

Was this helpful?

Custom elements are the foundation of Aurelia applications. As a developer, you'll often create custom elements that consist of:

  • An HTML template (view)

  • A class acting as the view model

  • An optional CSS stylesheet

Naming Components

The component name, derived from the file name, must include a hyphen to comply with the Shadow DOM specifications (see ). This requirement is part of the W3C Web Components standard to ensure proper namespacing for custom HTML elements.

A common best practice is to use a consistent two or three-character prefix for your components. For instance, all Aurelia-provided components start with the prefix au-.

There are various ways to create custom components in Aurelia, from simple convention-based components to more explicit and configurable ones.

The creation process is flexible, allowing you to adopt the approach that best fits your project's needs.

Creating Components

Aurelia treats any exported JavaScript class as a component by default. As such, there's no difference between an Aurelia component and a vanilla JavaScript class at their core.

Here's an example of a basic Aurelia component. You might add logic and bindable properties as needed, but at its simplest, a component is just a class.

export class AppLoader {
  // Component logic goes here
}
<p>Loading...</p>

By convention, Aurelia pairs the app-loader.ts view model with a corresponding app-loader.html file.

Embrace Conventions

Using Aurelia's conventions offers several benefits:

  • Reduced boilerplate code.

  • Cleaner and more portable codebases.

  • Enhanced code readability and learnability.

  • Less setup and ongoing maintenance.

  • Smoother upgrades to new versions and different platforms.

Explicit Component Creation with @customElement

The @customElement decorator provides a way to define components, bypassing conventions explicitly.

app-loader.ts
import { customElement } from 'aurelia';
import template from './app-loader.html';

@customElement({
    name: 'app-loader',
    template
})
export class AppLoader {
  // Component logic goes here
}
<p>Loading...</p>

The @customElement decorator allows for a variety of customizations, such as defining a different HTML template or inline template string, specifying the element's tag name, and configuring other component properties that would otherwise be managed by Aurelia.

Here's an example of defining the template inline:

app-loader.ts
import { customElement } from 'aurelia';

@customElement({
    name: 'app-loader',
    template: '<p>Loading...</p>'
})
export class AppLoader {
  // Component logic goes here
}

This approach is useful for simple components that don't require a separate view file.

Configuring the @customElement Decorator

The @customElement decorator allows for several configuration options:

name

This option sets the HTML tag name for the component. For instance, specifying "app-loader" means the component can be used in views as <app-loader></app-loader>.

If you only need to set the name, you can use a simpler syntax:

import { customElement } from 'aurelia';

@customElement('app-loader')
export class AppLoader {
  // Component logic goes here
}

template

The template option allows you to define the content of your component's template. You can specify an external template file, an inline template string, or even set it to null for components that don't require a view:

import { customElement } from 'aurelia';

@customElement({
  name: 'app-loader',
  template: null
})
export class AppLoader {
  // Component logic goes here
}

Omitting the template property means Aurelia won't use conventions to locate the template.

dependencies

You can declare explicit dependencies within the @customElement decorator, which can be an explicit way to manage dependencies without using the <import> tag in your templates:

import { customElement } from 'aurelia';
import { NumberInput } from './number-input';

@customElement({
  name: 'app-loader',
  dependencies: [NumberInput]
})
export class AppLoader {
  // Component logic goes here
}

Programmatic Component Creation

Aurelia provides an API for creating components programmatically, which is especially useful for testing.

import { CustomElement } from '@aurelia/runtime-html';

export class App {
  MyField = CustomElement.define({
    name: 'my-input',
    template: '<input value.bind="value">'
  });

  // Application logic goes here
}

The CustomElement.define method allows for a syntax similar to the @customElement decorator, including dependencies and other configurations.

Components declaration with static property $au

Beside the custom element and CustomElement.define usages, it's also possible to to delcare a components using static $au property, like the following example:

export class AppLoader {
  static $au = {
    type: 'custom-element',
    name: 'app-loader',
    dependencies: [...]
  }
  // Component logic goes here
}

Similar to custom element components, custom attributes, binding behaviors and value converters can also be declared using the static property $au.

HTML-Only Components

It's possible to create components in Aurelia using only HTML without a corresponding view model.

The file name determines the component's tag name. For example, a file named app-loader.html would be used as <app-loader></app-loader>.

For instance, an HTML-only loader component might look like this:

app-loader.html
<p>Loading...</p>

To use this component, import and reference it:

<import from="./app-loader.html"></import>

<app-loader></app-loader>

HTML Components with Bindable Properties

You can create HTML components with bindable properties using the <bindable> custom element, which serves a similar purpose to the @bindable decorator in a view model:

app-loader.html
<bindable name="loading"></bindable>

<p>${loading ? 'Loading...' : ''}</p>

Here's how you would use it:

<import from="./app-loader.html"></import>

<app-loader loading.bind="isLoading"></app-loader>

Components Without Views

Though less common, there are times when you might need a component with a view model but no view. Aurelia allows for this with the @customElement decorator by omitting the template property.

For example, a loading indicator using the nprogress library might be implemented as follows:

import nprogress from 'nprogress';
import { bindable, customElement } from 'aurelia';

import 'nprogress/nprogress.css';

@customElement({
    name: 'loading-indicator',
    template: null // No view template
})
export class LoadingIndicator {
  @bindable loading = false;

  loadingChanged(newValue) {
    if (newValue) {
      nprogress.start();
    } else {
      nprogress.done();
    }
  }
}

In this example, nprogress manages the DOM manipulation, so a template isn't necessary.

Registering Your Components

To use your custom components, you must register them either globally or within the scope of their intended use.

Globally Registering a Component

Register a component globally in main.ts using the .register method:

import Aurelia from 'aurelia';
import { MyApp } from './my-app';
import { SomeElement } from './path-to/some-element';

Aurelia
  .register(SomeElement)
  .app(MyApp)
  .start();

Importing a Component Within a Template

To use a component within a specific template, import it using the <import> tag:

<import from="./path-to/some-element"></import>

To use a component but with an alias, import it using the <import> tag, together with the as attribute for the new name:

<import from="./path-to/some-element" as="the-element"></import>

To use alias for a specific resource on an import, using the <import> tag, together with the {name}.as attribute for the new name, with {name} being the resource name:

<import from="./path-to/some-element" my-element.as="the-element"></import>

If there are multiple resource exports with the same resource name (an element and an attribute with the same foo name, for example), the alias will be applied to both of them.

Containerless Components

Sometimes you may want to render a component without its enclosing tags, effectively making it "containerless."

Be cautious when using containerless components, as you lose the ability to reference the element's container tags, which can complicate interactions with third-party libraries or testing. Use containerless only when necessary.

Using the @customElement Decorator

Mark a component as containerless with the containerless property:

import { customElement, ICustomElementViewModel } from 'aurelia';

@customElement({
    name: 'my-component',
    containerless: true
})
export class MyComponent implements ICustomElementViewModel {
  // Component logic goes here
}

The @containerless Decorator

The @containerless decorator is an alternative way to indicate a containerless component:

import { ICustomElementViewModel } from 'aurelia';
import { containerless } from '@aurelia/runtime-html';

@containerless
export class MyComponent implements ICustomElementViewModel {
  // Component logic goes here
}

When using <my-component></my-component>, Aurelia will remove the surrounding tags, leaving only the inner content.

Containerless Elements in Views

Declare a containerless component inside a view using the <containerless> tag:

<containerless>
  <!-- Custom element markup goes here -->
</containerless>

Dependencies can also be declared within the template using the <import> tag or globally registered through .

While it's useful to know about this API, it's typically unnecessary to define custom elements within Aurelia applications. This method is more relevant for writing tests, which you can learn about .

For more on working with Aurelia's Dependency Injection and registering dependencies, see the .

Styling Components
Aurelia's Dependency Injection layer
here
Dependency Injection documentation