Livewire 2,157 (https://github.com/livewire/livewire 23,583 ) 4.4.6 (composer require livewire/livewire) injects its script into any page with a component, with no build step. make:livewire cart-qty creates a single-file component in resources/views/components (the ⚡ prefix just flags it in editors); --mfc splits it into a folder of .php and .blade.php files, and --class gives the Livewire 3 layout, a class in app/Livewire plus a view. This format replaces Volt, which has no Livewire 4 documentation.
<?php
use Livewire\Component;
new class extends Component
{
public int $qty = 1;
public float $price = 24.50;
public function add(): void { $this->qty++; }
public function remove(): void { $this->qty = max(1, $this->qty - 1); }
};
?>
<div class="flex items-center gap-2">
<button wire:click="remove" class="rounded border px-3">-</button>
<input type="number" wire:model.live.debounce.300ms="qty" class="w-16 rounded border">
<button wire:click="add" class="rounded border px-3">+</button>
<span>Total: ${{ number_format($qty * $price, 2) }}</span>
</div><livewire:cart-qty /> renders it on the server. /cart returned this markup; wire:snapshot (shortened) carries the state:
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<div wire:key="lw-4051955147-0" wire:snapshot="{"data":{"qty":1, ...}"
wire:effects="[]" wire:id="MW1pqJ7LWFHRSLxQgIeD" wire:name="cart-qty"
class="flex items-center gap-2">
<button wire:click="remove" class="rounded border px-3">-</button>
<input type="number" wire:model.live.debounce.300ms="qty" class="w-16 rounded border">
<button wire:click="add" class="rounded border px-3">+</button>
<span>Total: $24.50</span>
</div>