Client-side interactivity without the complexity. Counters, forms, tabs — the stuff users actually interact with.
Three components you'll actually use in real projects
PHPue handles your server-side logic. But when you need a dropdown to actually open, a counter to actually count, or a modal to actually appear — that's browser territory. AlpineJS lives there.
x-for (needs x-ssr extension)Simple rule: PHP owns the server. AlpineJS owns the browser. PHP handles data. AlpineJS handles clicks.
One line in your App.pvue header. That's it.
<header>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Add this -->
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<link rel="stylesheet" href="/assets/css/styles.css">
</header>
Done. AlpineJS is now available in every view and component.
The defer attribute means it loads after your HTML — no flickering.
Click a button. Number goes up. That's reactive UI in its simplest form.
Try it:
Three parts:
x-data="{ count: 0 }" — Creates a reactive scope with a count variable
@click="count++" — Increments count on click
x-text="count" — Displays and auto-updates the value
Here's where it gets good. PHP sets the initial value. AlpineJS takes over from there.
<script> $initialCount = 5; </script><template> <div x-data="{ count:{{ $initialCount }}}"> <button @click="count++"> Count: <span x-text="count">{{ $initialCount }}</span> </button> </div> </template>
1. PHP renders {{ $initialCount }} as 5 on the server
2. Browser receives x-data="{ count: 5 }"
3. AlpineJS takes over — count is now reactive client-side
4. The fallback between x-text tags shows "5" before AlpineJS loads
Always include a fallback value between x-text tags.
It renders instantly — no flicker while AlpineJS initializes.
x-model gives you two-way binding. Type in a field, see it update instantly. No JavaScript required.
Type below and watch the preview update:
Name:
Email:
Message:
Classic UI pattern. One activeTab variable controls which panel shows. Docs pages, settings panels, feature lists — all use this.
Click the tabs:
PHPue + AlpineJS = modern web apps without the bloat.
Guides, examples, and API references to build faster.
Join the community. Get help, share ideas.
AlpineJS's x-for uses template cloning. PHPue works with the real DOM. They don't play nice together.
<div p-for="$item in $items">
<span x-data="{ liked: false }">
{{ $item.name }}
<button @click="liked = !liked">
<span x-show="!liked">♡</span>
<span x-show="liked">♥</span>
</button>
</span>
</div>
PHPue handles the loop server-side. AlpineJS handles the like button client-side. Best of both.
<template x-for="item in items">
<div>...</div> <!-- Nope -->
</template>
If you really need x-for, grab the x-ssr extension for SSR and CSR sync.
x-data
Creates reactive scope
x-data="{ open: false }"
@click
Runs on click
@click="open = !open"
x-text
Sets text content
x-text="message"
x-show
Toggles visibility
x-show="isVisible"
x-model
Two-way form binding
x-model="username"
:class
Dynamic CSS classes
:class="{ 'active': isActive }"
Counters, forms, tabs — you can now add real interactivity to your PHPue apps.