Framework Comparisons

See how Aurelia's elegant syntax compares to other popular frameworks and libraries. This is just a basic comparison, but it should give you a good idea of how Aurelia compares to other frameworks and libraries.

Conditional Rendering

Conditional rendering allows you to render different content based on the state of your application.

<!-- Simple if binding -->
<div if.bind="isVisible">Hello World</div>

<!-- If/else rendering -->
<div if.bind="isAuthenticated">
  Welcome back, ${username}!
</div>
<div else>
  Please log in
</div>

Two-way Binding

Two-way binding allows you to bind a property to an input element and have the property update when the input changes.

<!-- Two-way binding -->
<input type="text" value.bind="username">
<p>Hello, ${username}!</p>

List Rendering

List rendering allows you to render a list of items.

<!-- List rendering with repeat.for -->
<ul>
  <li repeat.for="item of items">${item.name}</li>
</ul>

Event Handling

Event handling allows you to handle events from the DOM.

<!-- Simple click event -->
<button click.trigger="handleClick()">Click me</button>

<!-- Event with parameter -->
<button click.trigger="handleClick($event)">With Event</button>

<!-- Key events -->
<input keyup.trigger="handleKeyUp($event)">

Class & Style Binding

Class and style binding allows you to bind classes and styles to an element.

<!-- Class binding -->
<div class.bind="dynamicClass">Dynamic class</div>
<div class="${condition ? 'active' : 'inactive'}">Conditional</div>

<!-- Style binding -->
<div style.bind="dynamicStyles">Dynamic styles</div>
<div style="color: ${textColor}">Dynamic color</div>

Component Creation

Component creation allows you to create a new component.

// my-component.ts
@customElement({
  name: 'my-component',
  template: `
    <h1>\${message}</h1>
    <button click.trigger="sayHello()">Greet</button>
  `
})
export class MyComponent {
  message = 'Hello World';
  
  @bindable name: string;
  
  sayHello() {
    console.log(`Hello ${this.name}!`);
  }
}

Computed Properties

Computed properties are properties that are derived from other properties. They are cached and only re-evaluated when their dependencies change.

export class MyComponent {
  firstName = 'John';
  lastName = 'Doe';
  
  get fullName() {
    return `${this.firstName} ${this.lastName}`;
  }
}

<!-- Template -->
<div>${fullName}</div>

Template References

Template references allow you to reference elements in the template from the component definition without needing to query the DOM.

<!-- Template reference -->
<input ref="nameInput" type="text">
<button click.trigger="focusInput()">Focus</button>

// Component class
export class MyComponent {
  nameInput: HTMLInputElement;
  
  focusInput() {
    this.nameInput.focus();
  }
}

Lifecycle Hooks

Lifecycle hooks allow you to run code at specific stages of a component's lifecycle, such as when it mounts or unmounts.

export class MyComponent {
  data = null;

  attached() {
    // Runs when component is attached to DOM
    this.data = fetchData();
  }

  detaching() {
    // Runs before component is removed from DOM
    cleanup();
  }
}

Props & Event Emission

Props allow parent components to pass data to child components, while events allow child components to communicate back to parents.

// child-component.ts
import { bindable, EventAggregator } from 'aurelia';

export class ChildComponent {
  @bindable message: string;
  @bindable onUpdate: (value: string) => void;

  handleClick() {
    // Emit event to parent
    this.onUpdate?.('Updated value');
  }
}

<!-- Parent usage -->
<child-component
  message.bind="parentMessage"
  on-update.call="handleUpdate($event)">
</child-component>

Watchers & Observers

Watchers allow you to perform side effects in response to data changes.

import { watch } from 'aurelia';

export class MyComponent {
  username = '';

  @watch('username')
  usernameChanged(newValue, oldValue) {
    console.log(`Username changed from ${oldValue} to ${newValue}`);
    // Perform side effect
    validateUsername(newValue);
  }
}

Slots & Content Projection

Slots allow parent components to pass content into child components, enabling flexible and reusable component designs.

// card.html
<template>
  <div class="card">
    <div class="card-header">
      <au-slot name="header">Default Header</au-slot>
    </div>
    <div class="card-body">
      <au-slot>Default content</au-slot>
    </div>
  </div>
</template>

<!-- Usage -->
<card>
  <div au-slot="header">Custom Header</div>
  <p>Custom content goes here</p>
</card>

Forms & Validation

Form handling and validation patterns for user input.

import { newInstanceOf } from 'aurelia';
import { ValidationController, ValidationRules } from '@aurelia/validation';

export class MyForm {
  email = '';
  password = '';

  constructor(
    @newInstanceOf(ValidationController) private controller: ValidationController
  ) {
    ValidationRules
      .ensure('email').required().email()
      .ensure('password').required().minLength(8)
      .on(this);
  }

  async submit() {
    const result = await this.controller.validate();
    if (result.valid) {
      // Process form
    }
  }
}

<!-- Template -->
<form submit.trigger="submit()">
  <input type="email" value.bind="email & validate">
  <input type="password" value.bind="password & validate">
  <button type="submit">Submit</button>
</form>