Reactivity Reference

Marko's goal is to make it easy to represent performant experiences with rich client interactions. This is enabled through its reactivity system. The reactive system is how Marko determines what needs to update and when.

The core of Marko's reactive system is the <let> tag.

Reactive Variables

In Marko, Tag Variables, Tag Parameters, and input are all reactive. This means they are tracked by the Marko compiler and when these values are caused to update any dependent render expressions are also updated.

Render Expressions

Any expression within a .marko template that references a reactive variable is considered reactive and will be updated alongside that variable.

These reactive expressions may exist throughout the template in attributes, dynamic text, dynamic tag names, and script content.

Note

All JavaScript expressions withing the Marko template may be reactive with the exception of static statements (including import, export, static, server and client) which are evaluated once when the template is loaded.

<let/count=0/>

<button onClick() {
  count++;
}>
  Current: ${count}
</button>
let/count=0

button onClick() {
  count++;
}
  -- Current: ${count}

Here, a count Tag Variable is mutated by a button click. Because the text content of the button references count, it is automatically be kept in sync with the new value.

Caution

In some cases Marko may cause some expressions to evaluate together. This is why render expressions should be pure.

Tip

Marko is a compiled language, and its reactive graph is discovered at compile time instead of during runtime. This is in contrast with many of the other leading approaches, such as Signals in SolidJS and Hooks in React.

Scheduling Updates

Marko automatically batches work to ensure optimal performance. Any time a reactive variable is changed, its update is queued to ensure that multiple changes will be applied efficiently together.

This update queue is typically scheduled after a microtask.

If additional updates are scheduled after the queue is consumed but before the update is painted, they are deferred until the next frame. This accomplishes a few things:

  • Content ready to display to the user is not blocked.
  • It is not possible to lock up the application in an infinite update loop.
  • The update loop can be used to power animations (although CSS Animations & Transitions/ JS Web Animations API are preferred in most cases).

Contributors

Helpful? You can thank these awesome people! You can also edit this doc if you see any issues or want to improve it.