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

Form Objects

Extract form logic into dedicated classes for cleaner components and reusable validation.

Basic Usage

Create a Form Object to encapsulate form fields and validation rules:

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 = '';
}

Using in Component

Component
use App\LiVue\Forms\ContactForm;

class ContactPage extends Component
{
    public ContactForm $form;

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

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

        // Process the data...
        $this->form->reset();
    }
}
Template
<form @submit.prevent="livue.call('submit')">
    <input v-model="form.name">
    <span v-if="livue.errors['form.name']">
        {{ livue.errors['form.name'][0] }}
    </span>

    <input v-model="form.email">
    <span v-if="livue.errors['form.email']">
        {{ livue.errors['form.email'][0] }}
    </span>

    <textarea v-model="form.message"></textarea>

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

Available Methods

Method Description
fill($data) Populate form from array or model
all() Get all fields as array
only(['name', 'email']) Get only specified fields
except(['password']) Get all except specified fields
pull() Get data and reset form
reset() Reset fields to defaults
validate() Validate and return data (throws on error)
validateOnly('email') Validate a single field

Create/Edit Pattern

A single Form Object can handle both creating and editing:

class PostForm extends Form
{
    public ?Post $post = null;

    #[Validate('required|min:5')]
    public string $title = '';

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

    public function setPost(Post $post): static
    {
        $this->post = $post;
        $this->fill($post);
        return $this;
    }

    public function save(): Post
    {
        $validated = $this->validate();

        if ($this->post) {
            $this->post->update($validated);
            return $this->post;
        }

        $post = Post::create($validated);
        $this->reset();
        return $post;
    }
}

Multiple Forms

A component can have multiple forms with separate validation:

Component
class SettingsPage extends Component
{
    public ProfileForm $profile;
    public PasswordForm $password;

    public function updateProfile()
    {
        $this->profile->validate();
        // ...
    }

    public function updatePassword()
    {
        $this->password->validate();
        // ...
    }
}
Template
<!-- Profile Form -->
<input v-model="profile.name">
<span v-if="livue.errors['profile.name']">
    {{ livue.errors['profile.name'][0] }}
</span>

<!-- Password Form -->
<input type="password" v-model="password.current">
<input type="password" v-model="password.new">

Artisan Command

Generate a Form Object with Artisan:

php artisan make:livue-form Contact

# Creates: app/LiVue/Forms/ContactForm.php

Benefits

Cleaner Components

Form logic is extracted, keeping your components focused on behavior.

Reusable Validation

The same Form Object can be used across multiple components.

Testable

Form Objects can be unit tested independently of components.

Type Safety

Typed properties ensure data integrity and IDE support.