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.