Tracked Properties

@tracked Makes a Field Reactive

Tracked Properties

The tracked decorator is Ember's reactivity primitive — fields decorated with it trigger re-renders whenever they are set.

4 min read Level 2/5 #ember#reactivity#tracked
What you'll learn
  • Decorate fields with the tracked decorator
  • Set tracked values from action handlers
  • Use derived getters that read tracked values

Ember Octane’s reactivity is built on @tracked. Any field you decorate with it becomes reactive — writes invalidate templates and downstream getters that read it.

Basic Use

import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';

export default class Counter extends Component {
  @tracked count = 0;

  get double() {
    return this.count * 2;
  }

  @action
  inc() {
    this.count++;
  }
}

The template re-renders automatically when count is mutated. Notice double is just a getter — Glimmer sees it reads this.count and tracks it.

Mutate By Replacement

Tracked deep mutations are not picked up — you have to replace the reference:

@tracked items = [];

@action
add(item) {
  // BAD: this.items.push(item) — won't re-render
  this.items = [...this.items, item];
}

For convenience, tracked-built-ins offers TrackedArray and TrackedObject which track mutations under the hood.

Tracked On Any Class

@tracked works on services, utility classes, anything — not just components.

import Service from '@ember/service';
import { tracked } from '@glimmer/tracking';

export default class CartService extends Service {
  @tracked items = [];

  get count() {
    return this.items.length;
  }
}

Any template that reads cart.count will update when items is reassigned.

@action Decorator →