BETA We're building something new — all help is welcome! Contribute →

Component Setup

Write Vue Composition API logic directly in your Blade templates using @script.

Basic Usage

The @script directive lets you define Vue Composition API code (computed, watch, lifecycle hooks) directly in your Blade template.

<div>
    <p>Name: <strong v-text="name">{{ $name }}</strong></p>
    <p>Greeting: <strong v-text="greeting"></strong></p>
    <p>Local count: <strong v-text="localCount"></strong></p>

    <button @click="incrementLocal()">+1 Local</button>
    <button @click="livue.call('increment')">+1 Server</button>
</div>

@script
const greeting = computed(() => 'Hello, ' + name.value + '!');
const localCount = ref(0);

function incrementLocal() {
    localCount.value++;
}

watch(name, (newVal) => {
    console.log('Name changed to:', newVal);
});

onMounted(() => {
    console.log('Component mounted!');
});

return { greeting, localCount, incrementLocal };
@endscript

Available APIs

Inside @script, you have access to all Vue Composition APIs and your component's state:

Vue Composition API
  • ref() - Create reactive references
  • computed() - Computed properties
  • watch() - Watch changes
  • watchEffect() - Reactive effect
  • reactive() - Reactive objects
  • onMounted() - Mount lifecycle
  • onUnmounted() - Unmount lifecycle
  • nextTick() - DOM update timing
Component Access
  • name, count, etc. - PHP properties as refs
  • livue - The LiVue helper object
  • livue.call() - Call server methods
  • livue.set() - Update state
  • livue.errors - Validation errors

Server State as Refs

All your PHP public properties are available as Vue refs. Access them with .value:

@script
// 'name' and 'count' are PHP public properties
const greeting = computed(() => 'Hello, ' + name.value + '!');
const doubled = computed(() => count.value * 2);

// Watch server state changes
watch(count, (newVal, oldVal) => {
    console.log(`Count changed: ${oldVal} → ${newVal}`);
});

return { greeting, doubled };
@endscript

IDE Support

For syntax highlighting and autocompletion, wrap your code in a <script> tag. LiVue removes it automatically:

@script
<script>
// Now your IDE recognizes this as JavaScript!
const greeting = computed(() => 'Hello, ' + name.value);
const localCount = ref(0);

return { greeting, localCount };
</script>
@endscript

Rules

  • 1. Place @script outside the root <div>, at the end of your template
  • 2. Return an object with the bindings you want to expose to the template
  • 3. Only one @script block per template
  • 4. Local state (refs created in @script) resets on server re-render

@script vs #[Vue]

Both execute client-side JavaScript, but serve different purposes:

Aspect @script #[Vue]
Location Blade template PHP method
Execution On component mount When called via livue.call()
Best for Computed, watchers, lifecycle One-shot actions (reset, alert)
Returns Object with template bindings Nothing (side effects only)

Full Example

PHP Component
class ScriptTest extends Component
{
    public string $name = 'World';
    public int $count = 0;

    public function increment()
    {
        $this->count++;
    }
}
Result
  • greeting updates reactively when name changes
  • doubled updates when count changes (server)
  • localCount is pure client-side, no server calls
  • Watchers log changes to console