Advanced Livewire Form Objects:Tips, Tricks & Best Practices

  • Home
  • Livewire
  • Advanced Livewire Form Objects:Tips, Tricks & Best Practices
Front
Back
Right
Left
Top
Bottom
LIVEWIRE
Sanjeewa%20RupasingheThe Game-Changing Feature You Need to Know

Laravel Livewire Forms

If you’ve been building Laravel applications with Livewire, you might have noticed your components getting messy with validation rules, property declarations, and form logic all mixed together. That’s where Livewire Form Objects come in—a dedicated class for handling all your form logic separately. Think of Form Objects as a specialized container that holds your form data, validation rules, and submission logic in one clean, reusable package. Introduced in Livewire 3, this feature transforms how we build forms in Laravel.

VS
The Second Look

The Traditional Way vs. Form Objects

Much cleaner, right? All the validation and logic moves to a dedicated form class.

 

Traditional Livewire Component:
ContactUs.php
Copy to clipboard
class ContactUs extends Component
{
    #[Validate('required|min:3')]
    public $name = '';

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

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

    public function submit(): void
    {
        $this->validate();
        // Handle submission...
    }
}
ContactUs.php
Copy to clipboard
class ContactUs extends Component
{
    public ContactForm $form;
    
    public function submit(): void
    {
        $this->form->store();
    }
}
USE CASES

Creating Your First Form Object

#1
Step 1

Generate the Form Class

Laravel makes this incredibly easy with Artisan: php artisan livewire:form {Form name}
ContactUs.php
Copy to clipboard
<?php

// php artisan livewire:form ContactForm
// This creates a new form class at `app/Livewire/Forms/ContactForm.php`:

namespace App\Livewire\Forms;

use Livewire\Form;

class ContactForm extends Form
{
    public $name    = '';
    public $email   = '';
    public $message = '';
    
    public function rules(): array
    {
        return [
            'name'    => 'required|min:3',
            'email'   => 'required|email',
            'message' => 'required|min:10',
        ];
    }
}
#2
Step 2

Use It in Your Component


Laravel makes this incredibly easy with Artisan: php artisan livewire:form {Form name}
ContactUs.php
Copy to clipboard
<?php

namespace App\Livewire;

use Livewire\Component;
use App\Livewire\Forms\ContactForm;

class ContactUs extends Component
{
    public ContactForm $form;
    
    public function submit(): void
    {
        // Validate the form
        $this->form->validate();
        
        // Access form data
        Contact::create([
            'name'    => $this->form->name,
            'email'   => $this->form->email,
            'message' => $this->form->message,
        ]);
        
        // Flash a success message
        session()->flash('success', 'Message sent!');
        
        // Reset the form
        $this->form->reset();
    }
    
    public function render(): View
    {
        return view('livewire.contact-us');
    }
}
#3
Step 3

Bind It in Your View


The syntax is simple—just prefix your form properties with form.
contact-us.blade.php
Copy to clipboard
<form wire:submit="submit">
    <div>
        <label>Name</label>
        <input type="text" wire:model="form.name">
        @error('form.name') <span class="error">{{ $message }}</span> @enderror
    </div>
    
    <div>
        <label>Email</label>
        <input type="email" wire:model="form.email">
        @error('form.email') <span class="error">{{ $message }}</span> @enderror
    </div>
    
    <div>
        <label>Message</label>
        <textarea wire:model="form.message"></textarea>
        @error('form.message') <span class="error">{{ $message }}</span> @enderror
    </div>
    
    <button type="submit">Send Message</button>
</form>

Explore project snapshots or discuss custom solutions.

WHY

Why Use Form Objects?

Separation of Concerns
Your component stays focused on component logic while the form handles validation and data management. This follows the Single Responsibility Principle—one class, one job.
Reusability
Need the same form in multiple places? No problem. Both components now use the exact same validation and logic.
Copy to clipboard
// In different components
class UserProfile extends Component
{
    public ContactForm $form;
}

class AdminContact extends Component
{
    public ContactForm $form;
}
Easier Testing
Testing becomes straightforward when form logic is isolated
Better Organization
Large forms with 15+ fields? Form objects keep everything organized instead of cluttering your component with dozens of property declarations.
ADVANCED

Advanced Features

Custom Methods in Form Objects
Add your own business logic directly to the form. Now your component becomes even simpler.
ContactForm.php
Copy to clipboard
class ContactForm extends Form
{
    public $name    = '';
    public $email   = '';
    public $message = '';

    public function rules():array
    {
        return [
            'name'    => 'required|min:3',
            'email'   => 'required|email',
            'message' => 'required|min:10',
        ];
    }

    public function store(): Contact
    {
        // Validate
        $this->validate();

        // Create
        $contact = Contact::create($this->only(['name', 'email', 'message']));

        // Send notification
        Mail::to('[email protected]')->send(new ContactNotification($contact));

        // Form reset and retun
        $this->reset();
        return $contact;
    }
}
ContactUs.php
Copy to clipboard
public function submit(): void
{
    $this->form->store();
    session()->flash('success', 'Message sent!');
}
Real-Time Validation

Add live validation with the .live modifier:
contact-us.blade.php
Copy to clipboard
<input type="email" wire:model.live="form.email">
Conditional Validation

Add live validation with the .live modifier:
ContactForm.php
Copy to clipboard
public function rules(): array
{
    return [
        'name'    => 'required|min:3',
        'email'   => 'required|email',
        'company' => $this->is_business ? 'required' : 'nullable',
        'phone'   => $this->is_business ? 'required' : 'nullable',
    ];
}
REAL WORLD

Real-World Example

User Registration
Here’s a complete registration form using Form Objects:
RegistrationForm.php
Copy to clipboard
// app/Livewire/Forms/RegistrationForm.php
class RegistrationForm extends Form
{
    public $name                  = '';
    public $email                 = '';
    public $password              = '';
    public $password_confirmation = '';
    public $terms                 = false;
    
    public function rules(): array
    {
        return [
            'name'     => 'required|min:3',
            'email'    => 'required|email|unique:users,email',
            'password' => 'required|min:8|confirmed',
            'terms'    => 'accepted',
        ];
    }
    
    public function register(): void
    {
        $this->validate();
        
        $user = User::create([
            'name'     => $this->name,
            'email'    => $this->email,
            'password' => Hash::make($this->password),
        ]);
        
        Auth::login($user);
        
        return redirect()->route('dashboard');
    }
}
Register.php
Copy to clipboard
// app/Livewire/Register.php
class Register extends Component
{
    public RegistrationForm $form;
    
    public function register(): void
    {
        return $this->form->register();
    }
    
    public function render(): View
    {
        return view('livewire.register');
    }
}
SUMMARY

Key Takeaways

What are Form Objects?

Dedicated classes that encapsulate form data, validation, and logic—created with php artisan livewire:form FormName. Form Objects aren’t just a feature—they’re a pattern that makes your Laravel applications more maintainable and professional. Start using them today, and your future self will thank you.

Main Benefits:
When to Use:
Simple Syntax:

Good code is its own best documentation. Form Objects let your code speak for itself.

Caleb Porzio Creator of Livewire

Thank You for Spending Your Valuable Time

I truly appreciate you taking the time to read blog. Your valuable time means a lot to me, and I hope you found the content insightful and engaging!
Front
Back
Right
Left
Top
Bottom
FAQ's

Frequently Asked Questions

Regular Livewire properties are defined directly in your component class, which can make large forms cluttered and hard to maintain. Form Objects are separate classes that encapsulate all form-related logic—properties, validation rules, and submission methods—in one place. This keeps your component clean and makes the form logic reusable across multiple components. You create a Form Object with php artisan livewire:form FormName and use it by declaring public FormName $form; in your component.

Yes! That's one of the biggest advantages of Form Objects. Once you create a form class, you can reuse it in as many components as you need. For example, you might have a ContactForm that's used in both a public contact page and an admin dashboard. Both components simply declare public ContactForm $form; and they'll have access to the same validation rules and logic, ensuring consistency across your application.

After calling $this->form->validate(), you can access individual properties like $this->form->name or $this->form->email. For convenience, you can also use the only() method to grab multiple fields at once: $this->form->only(['name', 'email', 'message']). This is particularly useful when creating or updating database records, as you can pass the result directly to methods like Model::create().

Absolutely! You can use Livewire's .live modifier to trigger validation as users type: <input wire:model.live="form.email">. The form will automatically validate the field in real-time using the rules you defined in your Form Object's rules() method. You can also use .blur to validate when the user leaves a field, giving you full control over the validation experience.

Yes, and this is highly recommended! Form Objects aren't just for validation—you can add any form-related logic as custom methods. For example, you might create a store() method that validates the form, creates a database record, sends notifications, and resets the form all in one place. This keeps your component methods simple (just $this->form->store()) while keeping all the complex business logic organized in the Form Object where it belongs.

Comments are closed