v1 LiVue v1 is here — server-driven reactivity for Laravel using Vue.js Get Started →
Back to articles

LiVue Articles

How to Create a LiVue Form and Use It in a Component

Published March 9, 2026

If you are building forms in LiVue, Form Objects are the cleanest way to keep your component logic focused.

Instead of mixing fields, validation rules, and submission concerns directly in the component class, you move form state into a dedicated object and let the component orchestrate the flow.

This article keeps the setup intentionally minimal (required steps only), but adds the reasoning behind each step so the structure is easy to reuse.

If you need a full framework overview first, start from Installation and State Management.

Why this pattern works well

  • Your component stays smaller and easier to scan.
  • Form-specific validation lives in one place.
  • Reusing the same form in multiple components becomes straightforward.
  • Error handling remains consistent ($errors['form.field'] pattern).

In short: your component handles actions, the Form Object handles form state.

Required flow (high-level)

  1. Generate a Form Object.
  2. Define fields + validation in that class.
  3. Attach the form to a LiVue component.
  4. Bind fields in Blade and validate on submit.

1) Generate the Form Object

php artisan make:livue-form Contact

This creates:

  • app/LiVue/Forms/ContactForm.php

2) Define form fields and validation

Edit app/LiVue/Forms/ContactForm.php:

<?php

namespace App\LiVue\Forms;

use LiVue\Attributes\Validate;
use LiVue\Form;

class ContactForm extends Form
{
    #[Validate('required|min:2')]
    public string $name = '';

    #[Validate('required|email')]
    public string $email = '';

    #[Validate('required|min:10')]
    public string $message = '';
}

At this point you already have a reusable form contract: fields + rules are centralized in one class.

3) Use the Form Object in a LiVue component

<?php

namespace App\LiVue;

use App\LiVue\Forms\ContactForm;
use LiVue\Component;

class ContactPage extends Component
{
    public ContactForm $form;

    public function __construct()
    {
        parent::__construct();
        $this->form = new ContactForm();
    }

    public function submit(): void
    {
        $data = $this->form->validate();

        // Use $data (save, send mail, etc.)

        $this->form->reset();
    }

    protected function render(): string
    {
        return 'livue.contact-page';
    }
}

The component now has a single responsibility: receive user actions (submit) and decide what to do with validated data.

4) Bind form fields in the Blade template

<form @submit.prevent="submit()">
    <input type="text" v-model="form.name" placeholder="Name">
    <span v-if="$errors['form.name']">@{{ $errors['form.name'] }}</span>

    <input type="email" v-model="form.email" placeholder="Email">
    <span v-if="$errors['form.email']">@{{ $errors['form.email'] }}</span>

    <textarea v-model="form.message" placeholder="Message"></textarea>
    <span v-if="$errors['form.message']">@{{ $errors['form.message'] }}</span>

    <button type="submit">Send</button>
</form>

Notice the error keys:

  • form.name
  • form.email
  • form.message

That prefix is expected because the Form Object is mounted on the $form property.

Where to go next

That is the complete required flow: generate form, define fields, attach it to a component, bind fields, validate on submit.

Practical extension 1: real-time validation

Once the required flow is in place, the next useful step is live validation while users type.

Inside your component, call validateOnly() in updated* hooks:

public function updatedFormEmail(): void
{
    $this->form->validateOnly('email');
}

This keeps feedback immediate without validating the entire form on every keystroke.

Reference: State > Validation

Practical extension 2: one form for create and edit

You can keep one Form Object for both create and edit flows.

Typical approach:

  • in create mode, keep default form values
  • in edit mode, call $this->form->fill($model) in mount()
  • on submit, run the same $this->form->validate() path

This avoids duplicate components and keeps business rules in one place.

Reference: State > Form Objects