Installation
composer require aerni/livewire-forms
php artisan vendor:publish --tag=livewire-forms-config
Publish the config to customize default settings (e.g., reCAPTCHA keys, form view paths).
Create a Statamic Form
Define a form in Statamic (e.g., contact form) with a blueprint. Example fields:
fields:
name:
type: text
validate: required|min:3
email:
type: email
validate: required|email
Generate a Livewire Component Use Artisan to scaffold a Livewire component tied to your form:
php artisan make:livewire ContactForm
Integrate the Form in a Blade View
<livewire:contact-form form="contact" />
The form prop maps to your Statamic form handle.
Test Real-Time Validation Submit the form without JavaScript—Livewire handles validation server-side. Observe real-time feedback as users type.
contact.yml) with fields for name, email, and message.php artisan make:livewire ContactForm).public function submit()
{
$this->validate();
// Process submission (e.g., send email, save to DB)
session()->flash('success', 'Form submitted!');
$this->reset();
}
<livewire:contact-form form="contact" />
# contact.yml
fields:
name:
type: text
validate: required|min:3
display: "Full Name"
instructions: "Your legal name"
terms:
type: checkbox
validate: accepted
display: "I agree to the terms"
public $form = 'contact';
public function mount()
{
$this->fields = collect($this->formBlueprint()->fields)->mapWithKeys(function ($field) {
return [$field['handle'] => $field];
});
}
wire:model.lazy for fields to trigger validation on blur:
<input wire:model.lazy="name" type="text">
@error('name') <span>{{ $message }}</span> @enderror
public function rules()
{
return [
'name' => ['required', 'min:3'],
'email' => ['required', 'email'],
];
}
fields:
plan:
type: select
options:
basic: Basic Plan
pro: Pro Plan
display: "Select Plan"
pro_features:
type: checkboxes
options:
feature1: Feature 1
feature2: Feature 2
display: "Pro Features"
conditions:
plan: pro
public function updatedPlan($value)
{
$this->dispatchBrowserEvent('refresh-form');
}
display: "Name ({{ __('lang.key') }})"
public function getDisplayLabelAttribute($field)
{
return __($this->fields[$field]['display'] ?? '');
}
// config/livewire-forms.php
'spam_protection' => [
'driver' => 'honeypot',
// or 'recaptcha' with keys
],
public function submit()
{
$this->validate([
'honeypot' => 'required|honey:field',
]);
// Proceed with submission
}
resources/views/vendor/livewire-forms/form.blade.php) by publishing the views:
php artisan vendor:publish --tag=livewire-forms-views
fields:
avatar:
type: upload
validate: max:1024
public function submit()
{
$this->validate();
$file = $this->avatar;
$path = $file->store('avatars');
// Save path to DB
}
<div x-data="{ showProFeatures: false }">
<input wire:model="plan" @change="showProFeatures = ($event.target.value === 'pro')">
<div x-show="showProFeatures">
<livewire:pro-features-form />
</div>
</div>
protected function rules()
{
return [
'age' => ['required', 'integer', 'min:18'],
'custom_rule' => ['custom_rule:param'],
];
}
AppServiceProvider:
Validator::extend('custom_rule', function ($attribute, $value, $parameters) {
return $value === $parameters[0];
});
afterSubmitting hook to log submissions or trigger events:
protected function afterSubmitting()
{
event(new FormSubmitted($this->formData));
return redirect()->route('thank-you');
}
php artisan statamic:clear-cached-data
php artisan livewire:discover to refresh Livewire components.wire:model.debounce.500ms to delay validation:
<input wire:model.debounce.500ms="email">
public function mount()
{
$this->site = Statamic::sites()->current();
}
ContactForm for contact form).How can I help you explore Laravel packages today?