Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Alpine on server-rendered pages

Alpine's main strength is working on top of HTML that the server produced. PHP, Laravel, Django or Rails render the whole page, and Alpine adds behavior to it: menus, tabs, a filter over an already rendered list. All you need is to pass data from the server code into x-data.

Data from Laravel Blade

In Laravel, templates live in resources/views. The controller passes an array of tasks to the template, and the Blade @js directive turns it into safe JavaScript:

<!-- resources/views/tasks/index.blade.php -->
<div x-data="{ tasks: @js($tasks), filter: 'all' }">
  <select x-model="filter">
    <option value="all">All</option>
    <option value="active">Active</option>
  </select>
 
  <ul>
    <template x-for="task in tasks.filter(t => filter === 'all' || !t.done)" :key="task.id">
      <li x-text="task.title"></li>
    </template>
  </ul>
</div>

The server replaces @js($tasks) with a ready array of objects, and the browser gets a regular x-data with data. The filter works without any server requests. The Alpine script itself is loaded in the shared layout, for example resources/views/layouts/app.blade.php, or through Vite, as in the installation lesson.

Data from plain PHP

Without Blade the same is done with json_encode, and the result is escaped with htmlspecialchars so quotes in the data do not break the attribute. In the template it is one line: the x-data value is built from json_encode($tasks) wrapped in htmlspecialchars(...). Laravel's @js directive does this for you.

Enhancing existing markup

You do not have to move data into JavaScript. Often the server renders the list as usual, and Alpine only adds behavior:

<!-- resources/views/tasks/show.blade.php -->
<div x-data="{ open: false }">
  <h2>{{ $task->title }}</h2>
  <button @click="open = !open">Details</button>
  <div x-show="open" x-cloak>
    {{ $task->description }}
  </div>
</div>

Blade outputs the task text with {{ }}, and Alpine shows and hides the description. Without JavaScript the page still contains all the text. x-cloak is covered in the next lesson.

Livewire

Livewire is a Laravel package where UI components are written in PHP and page updates come from the server. Livewire 3 already contains Alpine and loads it by itself, so you must not add a separate Alpine script — otherwise it starts twice. Inside a Livewire component, the $wire object in Alpine expressions gives access to the PHP component's properties and methods: for example, @click="$wire.save()" calls the save method on the server.

Common mistake

Writing :class on a Blade component, that is, on a tag like <x-button>. For Blade, a colon means "the value is a PHP expression", so it tries to run the Alpine code as PHP. To have Blade pass the attribute to the HTML unchanged, use a double colon: ::class="{ active: open }". On plain HTML tags in a Blade template a single colon works as usual.

Thanks for reading!

Donate to the site — we work hard for you.