Laravel + Blade

PawaJS is designed for any backend. Because the Continuity Rendering Model encodes state in plain HTML attributes, you can drop reactive components straight into Blade templates.

Why Blade + PawaJS works so well

Unlike frameworks that require a Node.js SSR server, PawaJS only needs the final HTML. Laravel (or any PHP app) can render the markup, and the client runtime resumes reactivity instantly.

No Node on the server

Just serve HTML. PawaJS hydrates on the client.

Progressive enhancement

Start with static Blade, add reactivity only where needed.

Full Laravel ecosystem

Keep using Eloquent, policies, forms, and routes.

1. Include the PawaJS runtime

Add the script once in your main layout. CDN is the simplest option for most Laravel projects.

php

                 
{{-- resources/views/layouts/app.blade.php --}}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@yield('title', config('app.name'))</title>
    @vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body>
    <div id="app">
        @yield('content')
    </div>

    {{-- PawaJS runtime --}}
    <script type="module" src="https://cdn.jsdelivr.net/npm/pawajs"></script>
    <script type="module">
        // Start PawaJS on the root element
        window.$pawa.pawaStartApp(document.getElementById('app'));
    </script>
</body>
</html> 

        

Tip: If you prefer to manage the script with Vite, install pawajs via npm and import it in resources/js/app.js instead of using the CDN.

2. Using PawaJS directives inside Blade

You can write PawaJS directives (if, for-each, on-click, state-*, etc.) directly in any Blade file.

php

                 
{{-- resources/views/dashboard.blade.php --}}
@extends('layouts.app')

@section('content')
<div class="p-8">
    <h1 class="text-2xl font-bold mb-6">Welcome, {{ auth()->user()->name }}</h1>

    {{-- Inline reactive state --}}
    <div state-count="0" class="flex items-center gap-4">
        <button on-click="count.value--" class="btn">−</button>
        <span class="text-xl font-mono">@{count.value}</span>
        <button on-click="count.value++" class="btn">+</button>
    </div>
</div>
@endsection 

        

3. Passing Laravel data into PawaJS

The cleanest way is to embed initial state as a JSON object and let PawaJS pick it up.

php

                 
{{-- Controller --}}
public function index()
{
    $todos = auth()->user()->todos()->get(['id', 'title', 'completed']);

    return view('todos.index', [
        'initialTodos' => $todos,
    ]);
} 

        
php

                 
{{-- resources/views/todos/index.blade.php --}}
@extends('layouts.app')

@section('content')
<div
    id="todos-app"
    state-todos='@json($initialTodos)'
>
    <h1 class="text-2xl font-bold mb-4">My Todos</h1>

    <ul class="space-y-2">
        <li
            for-each="todo in todos.value"
            for-key="{{todo.id}}"
            class="flex items-center gap-3 p-3 rounded border"
        >
            <input
                type="checkbox"
                :checked="todo.completed"
                on-change="todo.completed = e.target.checked"
            >
            <span class="@{todo.completed ? 'line-through text-muted-foreground' : ''}">
                @{todo.title}
            </span>
        </li>
    </ul>

    <form
        class="mt-6 flex gap-2"
        on-submit.prevent="
            todos.value.push({
                id: Date.now(),
                title: newTodo.value,
                completed: false
            });
            newTodo.value = '';
        "
    >
        <input
            state-new-todo="''"
            value="@{newTodo.value}"
            on-input="newTodo.value = e.target.value"
            placeholder="Add a new todo..."
            class="input flex-1"
        >
        <button type="submit" class="btn">Add</button>
    </form>
</div>
@endsection 

        

4. Registering custom components

When you need more complex logic, define PawaJS components in a JavaScript file and register them.

js

                 
// resources/js/components/counter.js
import { html, $state, useInsert, RegisterComponent } from 'pawajs';

const Counter = ({ initial}) => {
    const count = $state(initial());

    useInsert({ count });

    return html`
        <div class="flex items-center gap-3">
            <button on-click="count.value--" class="btn">−</button>
            <span class="font-mono text-xl">@{count.value}</span>
            <button on-click="count.value++" class="btn">+</button>
        </div>
    `;
};

RegisterComponent(Counter); 

        
js

                 
// resources/js/app.js
import './bootstrap';
import './components/counter';   // registers <counter>

import { pawaStartApp } from 'pawajs';

document.addEventListener('DOMContentLoaded', () => {
    pawaStartApp(document.getElementById('app'));
}); 

        
php

                 
{{-- Blade usage --}}
&lt;counter :initial="5">&lt;/counter> 

        

5. Mixing Blade and PawaJS

Use Blade for server-side logic (auth, loops over large datasets, authorization) and PawaJS for interactive islands.

html

                 
@auth
    <div state-userid="{{ auth()->id() }}">
        <p>Logged in as {{ auth()->user()->name }}</p>

        {{-- Only the interactive part is reactive --}}
        <div state-likes="{{ $post->likes_count }}">
            <button on-click="likes.value++" class="btn">
                ❤️ @{likes.value}
            </button>
        </div>
    </div>
@else
    <a href="{{ route('login') }}" class="btn">Log in to like</a>
@endauth 

        

Best Practices

  • Prefer islands over full-page SPAs — Keep most of the page in Blade and only hydrate interactive sections.
  • Serialize carefully — Always use @json() when embedding PHP data into state-* attributes.
  • Escape when needed — Blade’s {{ }} is safe. When you need raw HTML inside a PawaJS template, use {!! !!} carefully.
  • CSRF — For forms that post back to Laravel, keep the standard @csrf token. PawaJS event handlers run client-side only.
  • Vite — When you grow beyond the CDN, install pawajs with npm and let Vite bundle your components.

Next Steps

You now have a solid foundation for using PawaJS inside Laravel.

Form handling example with laravel→