State from PHP
x-data="{^profile}": the page's PHP prepares an array, the ^ sigil writes it as JSON into the attribute, and Alpine makes it live - no braces of Alpine's in the template at all.
{^field}
x-datax-modelx-text
Live
AF
Ada Fernández
Lead engineer · Amsterdam
Builds things that render on the server and wake up in the browser.
The state as Alpine holds it
Edit it live
Two components, each with its own copy of the same JSON - change one, the other stays as PAD wrote it.
Preview: ,
Requests to PAD
Nothing yet - use the example above, and every request a component makes to PAD shows here.
How it is built
PAD, on the server Alpine, in the browser
<div class="cols-2">
<div class="card profile" x-data="{^profile}">
<div class="profile-head">
<span class="avatar">AF</span>
<div>
<h3 x-text="name">{$profile.name}</h3>
<div class="muted small"><span x-text="role">{$profile.role}</span> · <span x-text="city">{$profile.city}</span></div>
</div>
</div>
<p x-text="bio">{$profile.bio}</p>
<div class="chips">
<template x-for="one in skills" :key="one"><span class="badge" x-text="one"></span></template>
</div>
<div class="profile-actions">
<button @click="liked = ! liked; likes += liked ? 1 : -1" :class="liked && 'is-liked'">
<span x-text="liked ? '♥' : '♡'"></span> <span x-text="likes">{$profile.likes}</span>
</button>
<form class="add-skill" @submit.prevent="skill.trim() && skills.push(skill.trim()); skill = ''">
<input class="input" x-model="skill" placeholder="Add a skill" aria-label="Add a skill">
</form>
</div>
<details class="panel state-dump">
<summary>The state as Alpine holds it</summary>
<pre x-text="JSON.stringify($data, null, 2)"></pre>
</details>
</div>
<div class="panel">
<div class="panel-title">Edit it live</div>
<p class="muted small">Two components, each with its own copy of the same JSON - change one, the other stays as PAD wrote it.</p>
<div x-data="{^profile}" class="stack-fields">
<label class="label">Name <input class="input" x-model="name"></label>
<label class="label">Role <input class="input" x-model="role"></label>
<p class="small">Preview: <strong x-text="name"></strong>, <span x-text="role"></span></p>
</div>
</div>
</div><?php
// The state of the card: an array of the page's PHP, written into x-data as JSON by the ^
// sigil - escaped for the attribute, so a quote or a brace in a value stays text. Alpine
// reads it as the object it is and keeps it live; nothing goes back to the server.
$profile = [ 'name' => 'Ada Fernández',
'role' => 'Lead engineer',
'city' => 'Amsterdam',
'bio' => 'Builds things that render on the server and wake up in the browser.',
'likes' => 12,
'liked' => FALSE,
'skills' => [ 'PHP', 'PAD', 'Alpine', 'SQL' ],
'skill' => '' ];
?>