A powerful, flexible form builder package for FilamentPHP that enables you to create, manage, and process dynamic forms with advanced features including custom field types, email templates, bulk sending capabilities, and comprehensive submission tracking.
A powerful, flexible form builder package for FilamentPHP that enables you to create, manage, and process dynamic forms with advanced features including custom field types, email templates, bulk sending capabilities, and comprehensive submission tracking.
Filament Form Builder is a comprehensive solution for building and managing forms within the FilamentPHP ecosystem. It provides a visual form builder interface, customizable field types, advanced email templating, and robust submission management.
This package requires a valid license to use. You can get your license here: Filament Form Builder
To install you'll need to add the repository to your composer.json file:
{
"repositories": [
{
"type": "composer",
"url": "https://satis.afsakar.com"
}
]
}
Once the repository has been added to the composer.json file, you can install Filament Form builder like any other composer package using the composer require command:
composer require afsakar/filament-form-builder
You will be prompted to provide your username and password. The username will be the email address and the password will be equal to your license key.
Loading composer repositories with package information
Authentication required (satis.afsakar.com):
Username: [license-email]
Password: [license-key]
Next, add the plugin's views to your custom theme in your theme.css file:
@source '../../../../vendor/afsakar/filament-form-builder/resources/views/**/*.blade.php';
@source '../../../../vendor/afsakar/filament-form-builder/src/**/*.php';
Afterward, run npm run build or yarn build to compile assets.
Publish the configuration file:
php artisan vendor:publish --tag="form-builder-config"
Publish the migration files:
php artisan vendor:publish --tag="form-builder-migrations"
Publish the render type images used in the form builder:
php artisan vendor:publish --tag="form-builder-images"
Publish Spatie Media Library migrations if you haven't done so:
php artisan vendor:publish --provider="Spatie\MediaLibrary\MediaLibraryServiceProvider" --tag="medialibrary-migrations"
Execute the migrations to create the necessary database tables:
php artisan migrate
This will create all necessary tables including:
The package includes backfill migrations that automatically populate template snapshots for any existing records.
If you want to customize the views:
php artisan vendor:publish --tag="form-builder-views"
Register the plugin in your Filament Panel provider (typically app/Providers/Filament/AdminPanelProvider.php):
use Afsakar\FilamentFormBuilder\FilamentFormBuilderPlugin;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->plugins([
FilamentFormBuilderPlugin::make(),
]);
}
Add styles to your theme.css file and run npm run build to compile your assets.
@source '../../../../vendor/afsakar/filament-form-builder/resources/views/**/*.blade.php';
@source '../../../../vendor/afsakar/filament-form-builder/src/**/*.php';
Add these variables to your .env file to customize email queue settings:
FORM_BUILDER_EMAIL_CHUNK_SIZE=50
FORM_BUILDER_EMAIL_CHUNK_DELAY=5
FORM_BUILDER_EMAIL_QUEUE=default
The configuration file config/form-builder.php allows you to customize various aspects:
You can override the default models:
'models' => [
'form' => \Afsakar\FilamentFormBuilder\Models\Form::class,
'form_section' => \Afsakar\FilamentFormBuilder\Models\FormSection::class,
'form_field' => \Afsakar\FilamentFormBuilder\Models\FormField::class,
'form_submission' => \Afsakar\FilamentFormBuilder\Models\FormSubmission::class,
'form_send' => \Afsakar\FilamentFormBuilder\Models\FormSend::class,
'email_template' => \Afsakar\FilamentFormBuilder\Models\EmailTemplate::class,
],
Define the model used for tracking who sends bulk emails:
'sender' => \App\Models\User::class,
Customize unique number prefixes for submissions and sends:
'number_prefix' => [
'submission' => 'SUB-',
'send' => 'SEND-',
],
Configure email sending performance:
'email_chunk_size' => 50, // Number of emails per chunk
'email_chunk_delay' => 5, // Seconds between chunks
'email_queue' => 'default', // Queue name
Register your custom field types:
'field_types' => [
\App\FormFields\CustomField::class,
],
Register your custom email blocks:
'email_blocks' => [
\App\EmailBlocks\CustomBlock::class,
],
Customize field type icons:
'icons' => [
'field_types' => [
'text' => Heroicon::OutlinedPencil,
'email' => Heroicon::OutlinedEnvelope,
// ...
],
],
For site-facing forms, use the Livewire component in your Blade template:
<livewire:form-renderer form-slug="contact-form" />
Or include it in your layout:
@livewire('form-renderer', ['formSlug' => 'contact-form'])
View and manage form submissions:
Create reusable email templates with a visual block builder:
Send templated emails to multiple recipients:
The system automatically chunks large recipient lists for optimal performance.
Quickly import multiple email addresses from CSV files:
Supported Formats:
Features:
Usage:
Example CSV Formats:
Simple list:
john@example.com
jane@example.com
bob@example.com
With header:
email
john@example.com
jane@example.com
Multi-column (email column auto-detected):
name,email,company
John Doe,john@example.com,ACME Corp
Jane Smith,jane@example.com,Tech Inc
Track email opens and engagement with powerful analytics:
Tracking Features:
How It Works:
UI Features:
Analytics Dashboard:
Total Recipients: 500
Opened: 350
Open Rate: 70%
Privacy Note: Email tracking uses standard industry practices (tracking pixels) and should be disclosed in your privacy policy. Recipients can disable image loading in their email client to opt out of tracking.
Generate a new field type using the artisan command:
php artisan make:field-type CustomField --icon=heroicon-o-star
This creates a new field type class in app/FormFields/CustomFieldField.php. Implement the required methods:
<?php
namespace App\FormFields;
use Afsakar\FilamentFormBuilder\FieldTypes\AbstractFieldType;
use Filament\Forms\Components\Field;
use Filament\Forms\Components\TextInput;
class CustomFieldField extends AbstractFieldType
{
public function getIdentifier(): string
{
return 'customfield';
}
public function getLabel(): string
{
return 'Custom Field';
}
public function getIcon(): \BackedEnum|string
{
return 'heroicon-o-star';
}
public function getConfigurationSchema(): array
{
return [
TextInput::make('custom_option')
->label('Custom Option')
->default('default_value'),
];
}
public function getDefaultConfiguration(): array
{
return [
'custom_option' => 'default_value',
];
}
public function getValidationRules(array $configuration, bool $isRequired): array
{
$rules = $this->getBaseRules($isRequired);
// Add custom validation rules
$rules[] = 'string';
$rules[] = 'max:255';
return $rules;
}
public function getFilamentComponent(
string $name,
string $label,
array $configuration,
bool $isRequired,
?string $placeholder = null,
?string $helpText = null,
?int $columnSpan = 1
): Field {
$component = TextInput::make($name);
return $this->applyCommonProperties(
$component,
$label,
$isRequired,
$placeholder,
$helpText
);
}
}
Register the field type in config/form-builder.php:
'field_types' => [
\App\FormFields\CustomFieldField::class,
],
Generate a new email block using the artisan command:
php artisan make:email-block CustomBlock --icon=heroicon-o-cube
This creates:
app/EmailBlocks/CustomBlockBlock.phpresources/views/email-blocks/custom-block.blade.phpImplement the block class:
<?php
namespace App\EmailBlocks;
use Afsakar\FilamentFormBuilder\EmailBlocks\AbstractEmailBlock;
use Filament\Forms\Components\ColorPicker;
use Filament\Forms\Components\Textarea;
class CustomBlockBlock extends AbstractEmailBlock
{
public static function getIdentifier(): string
{
return 'custom-block';
}
public static function getLabel(): string
{
return 'Custom Block';
}
public static function getIcon(): \BackedEnum|string
{
return 'heroicon-o-cube';
}
public static function getSchema(): array
{
return [
Textarea::make('content')
->label('Content')
->required()
->rows(3),
ColorPicker::make('background_color')
->label('Background Color')
->default('#ffffff'),
];
}
public static function getDefaultData(): array
{
return [
'content' => 'Custom block content',
'background_color' => '#ffffff',
];
}
public static function getView(): string
{
return 'email-blocks.custom-block';
}
}
Customize the view (resources/views/email-blocks/custom-block.blade.php):
<div style="background-color: {{ $background_color ?? '#ffffff' }}; padding: 20px; margin: 10px 0;">
<div style="font-size: 16px; line-height: 1.5;">
{!! nl2br(e($content ?? '')) !!}
</div>
</div>
Register the email block in config/form-builder.php:
'email_blocks' => [
\App\EmailBlocks\CustomBlockBlock::class,
],
The package fires several events that you can listen to:
Fired when a form is submitted:
use Afsakar\FilamentFormBuilder\Events\FormSubmitted;
use Illuminate\Support\Facades\Event;
Event::listen(FormSubmitted::class, function (FormSubmitted $event) {
$submission = $event->submission;
// Your custom logic
});
Fired when an email is sent:
use Afsakar\FilamentFormBuilder\Events\EmailSent;
use Illuminate\Support\Facades\Event;
Event::listen(EmailSent::class, function (EmailSent $event) {
$formSend = $event->formSend;
// Your custom logic
});
Fired when a bulk email send is created:
use Afsakar\FilamentFormBuilder\Events\FormSendCreated;
use Illuminate\Support\Facades\Event;
Event::listen(FormSendCreated::class, function (FormSendCreated $event) {
$formSend = $event->formSend;
// Your custom logic
});
The package includes comprehensive test coverage using Pest PHP.
Run all tests:
composer test
Run only feature tests:
vendor/bin/pest tests/Feature
Run only unit tests:
vendor/bin/pest tests/Unit
Example test structure:
use Afsakar\FilamentFormBuilder\Models\Form;
use Afsakar\FilamentFormBuilder\Services\FormSubmissionService;
it('can submit a form', function () {
$form = Form::factory()->create([
'type' => 'site',
'is_active' => true,
]);
$service = app(FormSubmissionService::class);
$submission = $service->submit($form, [
'name' => 'John Doe',
'email' => 'john@example.com',
]);
expect($submission)->toBeInstanceOf(\Afsakar\FilamentFormBuilder\Models\FormSubmission::class);
expect($submission->data['name'])->toBe('John Doe');
});
Run PHPStan analysis:
composer analyse
Run Laravel Pint (code formatting):
composer lint
The package creates the following tables:
Handles form submission processing:
$service = app(\Afsakar\FilamentFormBuilder\Services\FormSubmissionService::class);
// Submit a form
$submission = $service->submit($form, $data);
// Submit using DTO
$submission = $service->submitFromDto($formSubmissionData);
Handles bulk email sending:
$service = app(\Afsakar\FilamentFormBuilder\Services\FormSendService::class);
// Send to multiple recipients
$service->sendToMultipleRecipients($emailTemplate, $recipients, $subject, $data);
Renders form components:
$service = app(\Afsakar\FilamentFormBuilder\Services\FormRenderService::class);
// Get form components
$components = $service->getFormComponents($form);
Manages field type registration:
$registry = app(\Afsakar\FilamentFormBuilder\Services\FieldTypeRegistry::class);
// Get all field types
$fieldTypes = $registry->all();
// Get specific field type
$fieldType = $registry->get('text');
The package automatically preserves email templates at the time of sending or submission. This ensures data integrity and audit compliance.
When a form is submitted or an email is sent, the package creates a snapshot of the associated email template, including:
// When creating a submission - snapshot is automatic
$service = app(\Afsakar\FilamentFormBuilder\Services\FormSubmissionService::class);
$submission = $service->submit($form, $data);
// Template snapshot is automatically saved with the submission
// When sending emails - snapshot is automatic
$service = app(\Afsakar\FilamentFormBuilder\Services\FormSendService::class);
$formSend = $service->sendEmailFromDto($dto);
// Template snapshot is automatically saved with the send record
When previewing or sending emails, the system automatically uses the snapshot if available:
// In PreviewFormSubmissionAction
if ($submission->template_content_blocks || $submission->template_content) {
// Uses snapshot - preserves original template
$snapshotTemplate = new EmailTemplate([...]);
} else {
// Falls back to current template for old records
}
Implement the CanProcessSubmission contract to add custom processing logic:
use Afsakar\FilamentFormBuilder\Contracts\CanProcessSubmission;
use Afsakar\FilamentFormBuilder\Models\FormSubmission;
class CustomProcessor implements CanProcessSubmission
{
public function process(FormSubmission $submission): void
{
// Your custom logic
// e.g., send to external API, trigger workflows, etc.
}
}
Create forms programmatically:
use Afsakar\FilamentFormBuilder\Models\Form;
use Afsakar\FilamentFormBuilder\Models\FormSection;
use Afsakar\FilamentFormBuilder\Models\FormField;
$form = Form::create([
'title' => 'Contact Form',
'slug' => 'contact-form',
'type' => 'site',
'status' => 'active',
'is_active' => true,
]);
$section = $form->sections()->create([
'title' => 'Personal Information',
'grid_columns' => 2,
'order' => 1,
]);
$section->fields()->create([
'type' => 'text',
'name' => 'name',
'label' => 'Full Name',
'is_required' => true,
'order' => 1,
]);
$section->fields()->create([
'type' => 'email',
'name' => 'email',
'label' => 'Email Address',
'is_required' => true,
'order' => 2,
]);
For high-volume email sending, configure a dedicated queue:
// config/queue.php
'connections' => [
'form-emails' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => 'form-emails',
'retry_after' => 90,
],
],
Update your .env:
FORM_BUILDER_EMAIL_QUEUE=form-emails
Run the queue worker:
php artisan queue:work --queue=form-emails
The package includes comprehensive analytics widgets for tracking form submissions and sent emails. All widgets are automatically registered and available for use.
Displays key statistics about form submissions with interactive charts:
Displays key statistics about sent forms:
Interactive line chart showing submission trends with multiple time range filters:
Bar chart displaying submission counts per form (top 10 active forms with color-coded bars).
Table widget showing the 5 most recent submissions with quick view actions.
Table widget showing the 5 most recent sent forms with quick view actions.
Widgets are automatically displayed on their respective resource list pages:
// In ListFormSubmissions.php
protected function getHeaderWidgets(): array
{
return [
FormSubmissionStatsWidget::class,
FormSubmissionsChartWidget::class,
FormSubmissionsByFormWidget::class,
];
}
To display widgets on your Filament dashboard, add them to your dashboard configuration:
// In your Dashboard page
use Afsakar\FilamentFormBuilder\Filament\Widgets\FormSubmissionStatsWidget;
use Afsakar\FilamentFormBuilder\Filament\Widgets\FormSendStatsWidget;
use Afsakar\FilamentFormBuilder\Filament\Widgets\LatestFormSubmissionsWidget;
protected function getHeaderWidgets(): array
{
return [
FormSubmissionStatsWidget::class,
FormSendStatsWidget::class,
];
}
protected function getFooterWidgets(): array
{
return [
LatestFormSubmissionsWidget::class,
];
}
You can customize widgets by extending them:
use Afsakar\FilamentFormBuilder\Filament\Widgets\FormSubmissionStatsWidget;
class CustomSubmissionStats extends FormSubmissionStatsWidget
{
protected static ?int $sort = 10;
protected function getStats(): array
{
$stats = parent::getStats();
// Add your custom stats
$stats[] = Stat::make('Custom Metric', $value)
->description('Custom description')
->color('info');
return $stats;
}
}
is_active is set to truephp artisan storage:linkconfig/filesystems.php.envfailed_jobs table for errorsFORM_BUILDER_EMAIL_CHUNK_SIZEFORM_BUILDER_EMAIL_CHUNK_DELAYIf you discover any security-related issues, please email afsakarr@gmail.com instead of using the issue tracker.
If you have a question, bug or feature request, please e-mail me at afsakarr@gmail.com Love to hear from you!
Find the perfect tools to enhance your development workflow.
View All Products