labrodev/contactable
Configurable Livewire contact form for Laravel. Define fields in config, optionally persist submissions to an Eloquent model, and send notifications via mail, log, or webhook. Supports published views and translation-ready labels/messages.
Installation:
composer require labrodev/contactable
php artisan vendor:publish --tag=contactable-config
Publish the default config (config/contactable.php) and update it to match your needs.
Basic Blade Integration: Add the Livewire component to your form:
@livewire('contactable::contact-form')
First Use Case:
name, email, and message fields in config/contactable.php:
'fields' => [
'name' => [
'type' => 'text',
'label' => 'contactable::fields.name.label',
'rules' => 'required|string|max:255',
],
'email' => [
'type' => 'email',
'label' => 'contactable::fields.email.label',
'rules' => 'required|email',
],
'message' => [
'type' => 'textarea',
'label' => 'contactable::fields.message.label',
'rules' => 'required|string',
],
],
mail):
'notify' => [
'channel' => 'mail',
'options' => [
'to' => 'contact@example.com',
],
],
Dynamic Field Configuration:
Extend or override the default fields in config/contactable.php or via a service provider:
Contactable::configure(function ($config) {
$config->fields['phone'] = [
'type' => 'tel',
'label' => 'Phone Number',
'rules' => 'nullable|digits_between:10,15',
];
});
Model Persistence:
App\Models\ContactRequest) with fillable fields matching your config.config/contactable.php:
'model' => App\Models\ContactRequest::class,
ContactRequest::observe(ContactableObserver::class);
Notification Channels:
resources/views/vendor/contactable/mail.blade.php).'notify' => [
'channel' => 'log',
'options' => [
'path' => storage_path('logs/contactable.log'),
],
],
'notify' => [
'channel' => 'webhook',
'options' => [
'url' => 'https://api.example.com/webhook',
'headers' => ['Authorization' => 'Bearer token'],
],
],
Validation and Localization:
contactable::validation.required).resources/lang/en/contactable.php:
return [
'fields' => [
'name' => [
'label' => 'Full Name',
],
],
];
Styling and Assets:
php artisan vendor:publish --tag=contactable-assets
resources/views/vendor/contactable/form.blade.php).Livewire Events: Listen for form submission events in your parent component:
protected $listeners = ['contactable.submitted' => 'handleSubmission'];
public function handleSubmission($data) {
// Custom logic after submission
}
Form Spam Protection:
Add reCAPTcha or honeypot fields via the fields config:
'fields' => [
'honeypot' => [
'type' => 'hidden',
'rules' => 'required|ignore',
],
],
API Endpoints: For headless use, create a Livewire action to submit via JavaScript:
Livewire.emit('contactable.submit', { name: 'John', email: 'john@example.com' });
Testing: Use Livewire’s testing helpers to simulate submissions:
$this->livewire(Contactable::class)
->fillForm([
'name' => 'Test User',
'email' => 'test@example.com',
'message' => 'Hello!',
])
->call('submit')
->assertEmitted('contactable.submitted');
Field Key Conflicts:
Ensure key values in fields are unique and match your model’s fillable fields if using persistence. Overlapping keys may cause validation or storage issues.
Notification Channel Errors:
to address is valid and the mail driver is configured in Laravel.url and headers for typos or CORS issues. Use try-catch in the webhook handler:
try {
Http::post($url, $data)->throw();
} catch (\Throwable $e) {
Log::error("Webhook failed: " . $e->getMessage());
}
path is writable and the directory exists.Livewire Component Registration:
If using the component outside the contactable namespace, register it in AppServiceProvider:
Livewire::component('contact-form', \Labrodev\Contactable\Livewire\ContactForm::class);
CSRF Token Mismatch:
Ensure the form includes @csrf and the Livewire component is loaded after @livewireScripts.
Translation Fallback: If using custom translation keys, ensure they exist in your language files or fall back to the default:
'label' => __('contactable::fields.name.label', [], 'en'), // Fallback to English
Validation Errors:
Check the Livewire component’s errors property or log them:
Log::debug('Validation errors:', $this->errors->all());
Submission Data:
Log the submitted data in the handleSubmit method of the Livewire component (extend if needed):
protected function handleSubmit(array $data): void
{
Log::debug('Submitted data:', $data);
// ... rest of the logic
}
Configuration Overrides:
Use php artisan config:clear after updating config/contactable.php to apply changes.
Custom Validation: Extend the Livewire component to add dynamic rules:
public function mount()
{
$this->rules['custom_field'] = 'required_if:other_field,1|string';
}
Additional Channels:
Add a new notification channel by implementing Labrodev\Contactable\Contracts\NotifyChannel:
class SlackChannel implements NotifyChannel
{
public function notify(array $data): void
{
// Send to Slack
}
}
Register it in the config:
'notify' => [
'channel' => 'slack',
'options' => ['webhook_url' => env('SLACK_WEBHOOK')],
],
Model Events:
Listen for creating or created events on your model to add metadata (e.g., IP address):
ContactRequest::created(function ($request) {
$request->ip_address = request()->ip();
});
Asset Overrides: Publish and override the default CSS/JS:
php artisan vendor:publish --tag=contactable-assets --force
Customize resources/vendor/contactable/assets/contactable.css.
Multi-Step Forms:
Use Livewire’s wire:ignore and JavaScript to toggle steps dynamically, then submit via the component’s submit method.
How can I help you explore Laravel packages today?