Dynamic composition
Render components and templates dynamically with Aurelia's au-compose element.
Dynamic composition lets you decide what to render at runtime instead of at compile time. Think of <au-compose> as a placeholder that can become any component or template based on your application's state, user preferences, or data.
This is perfect for:
Dashboard widgets that change based on user configuration
Conditional components where you need to render different components based on data
Plugin architectures where components are loaded dynamically
Form builders that render different field types
Content management where layout components vary by content type
Before you start: Make sure you are comfortable with components and template controllers; both concepts show up throughout the examples.
Quick Reference
component
Registered element name (string), custom element class/definition, plain object, or Promise resolving to either
undefined
Chooses which component to render; strings must match a globally or locally registered custom element or Aurelia will throw.
template
Literal HTML string or Promise<string>
undefined
Provides markup for template-only composition. Ignored when component resolves to a custom element.
model
Any value
undefined
Passed into the composed component's activate(model) hook. Updating model re-runs activate without recreating the component.
scope-behavior
'auto' | 'scoped'
'auto'
Controls scope inheritance for template-only compositions (component omitted or resolves to null). Has no effect for custom elements.
tag
string | null
null (containerless)
For template-only compositions, provide a tag name when you need a surrounding element; leave as null to keep the default comment boundaries.
composition
ICompositionController (from-view)
undefined
Exposes the controller for the currently composed view so you can call controller.viewModel, update(model), or deactivate().
composing
Promise<void> | void (from-view)
undefined
Surfaces the pending composition promise so parents can show loading states or cancel work when newer compositions queue up.
Tip: Bindings placed on
<au-compose>that match bindables on the composed component are forwarded to that component. Attributes that do not match (for exampleclass,style, or event handlers) are applied to the generated host element instead.
Component Composition
Composing with Custom Element Definitions
You can compose any custom element by passing its definition to the component property. Define those elements once at module scope so Aurelia reuses the same definition instead of recreating it for every view-model instance:
Composing with Component Names
If you have components registered globally or imported, you can reference them by name:
Template-Only Composition
Sometimes you just need to render dynamic HTML without a full component. Template-only composition is perfect for this:
Basic Template Composition
Dynamic Templates with Data
Template with Component Object
You can combine a template with a simple object that provides data and methods:
Controlling the Host Element
Default Host Behavior
When you compose a custom element, it creates its own host element. But for template-only compositions, Aurelia doesn't create a wrapper element by default:
This renders as comment boundaries around your content:
Creating a Host Element with tag
tagWhen you need a wrapper element around your composed content, use the tag property:
This renders as:
Any attributes you put on <au-compose> (like class, style, or event handlers) get transferred to the host element.
Practical Host Element Example
Passing Data with Models and the Activate Method
Understanding the Activate Lifecycle
Composed components can implement an activate method that runs when the component is created and whenever the model changes. This is perfect for initialization and data updates:
Using Models for Data Passing
Model Updates vs Component Changes
Important distinction: changing the model doesn't recreate the component, it just calls activate() again. This is efficient for data updates:
Advanced Features
Promise Support
Both template and component properties can accept promises, perfect for lazy loading:
Scope Behavior Control
For template-only compositions, you can control whether they inherit the parent scope:
Accessing the Composition Controller
Use the composition property to access the composed component's controller:
Tracking Pending Compositions
Bind to composing whenever you need to surface intermediate loading states. Aurelia assigns the currently pending composition promise to your property, allowing you to show a spinner or cancel older requests when newer compositions queue up.
Real-World Examples
Form Builder with Dynamic Fields
Plugin Architecture with Dynamic Loading
Content Management with Dynamic Layouts
Migrating from Aurelia 1
If you're upgrading from Aurelia 1, here are the key changes you need to know:
Property Name Changes
Aurelia 1:
Aurelia 2:
Component Reference Changes
Aurelia 1:
Aurelia 2:
Note:
component.refon<au-compose>references theAuComposeelement itself, not the composed child. Usecomposition.controller.viewModelwhen you need the child instance.
Aurelia 2:
Scope Inheritance Changes
Aurelia 1:
Aurelia 2:
Migration Examples
Before (Aurelia 1):
After (Aurelia 2):
Dynamic Module Loading Migration
Aurelia 1:
Aurelia 2:
Value Converter Pattern for Remote Templates
If you need to load templates from URLs (like in Aurelia 1), create a value converter:
Common Migration Gotchas
Binding Transfer: In Aurelia 2, ALL bindings on
<au-compose>are passed to the composed componentActivation: The
activatemethod works the same but is now available on any component typeLifecycle: Custom elements get full lifecycle, plain objects get activate/deactivate only
Performance: Aurelia 2's composition is more efficient with better change detection
Best Practices
Use promises for lazy loading - Only load components when needed to improve performance
Leverage the activate method - Perfect for data initialization and updates
Consider scope behavior - Use
scopedwhen you want isolation,autofor inheritanceCache component definitions - Call
CustomElement.defineonce per module and reuse the reference instead of redefining inside constructors.Handle loading states - Bind to
composingto show a spinner or disable UI while Aurelia hydrates the next component.Use models efficiently - Changing models is cheaper than switching components because
activate(model)re-runs without rehydration.
Dynamic composition gives you the flexibility to build truly dynamic UIs that adapt to your users' needs, load efficiently, and scale with your application's complexity.
Next steps
Explore portalling elements to move DOM across layout boundaries.
Combine composition with enhance when progressively upgrading existing markup.
Review watching data to react to model changes that drive composition.
Last updated
Was this helpful?