Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

$el, $event and $nextTick

Magic properties are variables starting with $ that Alpine provides to every expression. You have already met $refs. Here are the three most useful ones: the element, the event, and waiting for the page to update.

$el

$el is the element the directive is on:

<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
 
<div x-data>
  <button @click="$el.textContent = 'Done'">Mark</button>
</div>

After a click the button label changes to "Done". In real code, keep the text in data and output it with x-text, and use $el for things like focus or element sizes.

$event

$event is the event object — the same one a function passed to addEventListener receives. It holds the typed value, the pressed key, coordinates:

<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
 
<div x-data>
  <input @keydown="console.log($event.key)" placeholder="Press some keys">
</div>

Every pressed key is printed in the console under the example: a, Enter, Backspace.

If the handler is a method name without parentheses, Alpine passes the event as the first argument:

<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
 
<div x-data="{
  search: '',
  update(event) {
    this.search = event.target.value;
  }
}">
  <input @input="update" placeholder="Search tasks">
  <p x-text="'Searching for: ' + search"></p>
</div>

@input="update" is the same as @input="update($event)".

$nextTick

Alpine does not update the page instantly but right after the current code finishes. $nextTick delays a function until the update has happened:

<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
 
<div x-data="{ tasks: ['Buy milk'] }">
  <button @click="
    tasks.push('Call Oleg');
    console.log('Right away:', $refs.list.children.length);
    $nextTick(() => console.log('After the update:', $refs.list.children.length));
  ">Add</button>
  <ul x-ref="list">
    <template x-for="task in tasks">
      <li x-text="task"></li>
    </template>
  </ul>
</div>

After the first click the console shows "Right away: 2" and "After the update: 3". The list has one more child than there are tasks because the <template> itself sits in it. The point is that the new <li> exists only by the time of $nextTick.

Other magic properties

PropertyWhat it is
$rootThe component's root element, the one with x-data
$dataThe component's data object
$dispatchSends a custom event
$watchWatches a property
$storeGlobal store

$dispatch and $watch are the next lesson, $store comes in the lesson on global state.

Common mistake

Expecting this.$el inside a method to be the button that was clicked. In methods from x-data, this.$el points to the component's root element, the one with x-data. To get the button, pass it explicitly — @click="mark($el)" — or take $event.target from the event.

Thanks for reading!

Donate to the site — we work hard for you.