Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Filament Form Builder Laravel Package

tapp/filament-form-builder

Filament plugin for building forms in the admin panel and collecting user data on the front end. Supports Filament field components, Laravel validation rules, response rendering, CSV export, sorting, and multi-tenancy-aware migrations.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Install (VCS, not Packagist)

Since the package isn't on Packagist yet, add the repository first, then require it:

{
  "repositories": [
    { "type": "vcs", "url": "https://github.com/TappNetwork/Filament-Form-Builder" }
  ]
}
composer require tapp/filament-form-builder:"^4.0"

Check the version matrix before you start: Filament 4.x/5.x → package 4.x, Filament 3.x → package 1.x. Requirements are PHP 8.2+, Laravel 11+, and it pulls in maatwebsite/excel and spatie/eloquent-sortable transitively.

2. Publish and migrate

php artisan vendor:publish --tag="filament-form-builder-migrations"
php artisan migrate

If you want to customize behavior, also publish config/views:

php artisan vendor:publish --tag="filament-form-builder-config"
php artisan vendor:publish --tag="filament-form-builder-views"

3. Register the right plugin per panel

The package splits admin and front-end concerns into three plugins, and you almost certainly need at least two:

// AdminPanelProvider — manage forms, fields, entries
->plugins([FilamentFormBuilderPlugin::make()])

// GuestPanelProvider — public form + entry pages
->plugins([FilamentFormBuilderGuestPlugin::make()])

// AppPanelProvider — authenticated form + entry pages
->plugins([FilamentFormBuilderFrontendPlugin::make()])

4. First use case

Log into the admin panel, create a form, add fields (each has a required type plus Laravel validation rules), then hit /forms/{form} to submit it. A record lands in the entries list, viewable at /entries/{entry} and exportable to CSV from the Entries relation manager. That round trip — build in admin, submit on front end, export — is the whole package in one pass.

Where to look first

  • config/filament-form-builder.php — panel IDs, route URIs, login route, options editor, tenancy
  • The published migrations — they decide tenant columns at migrate time, so read before running
  • Tapp\FilamentFormBuilder\Models\FilamentForm, FilamentFormField, FilamentFormUser — the data model
  • ShowForm / ShowEntry page classes — the override points for presentation

Implementation Patterns

Form authoring workflow

Treat the form resource as a schema editor with a lifecycle: create → add/sort fields → lock. spatie/eloquent-sortable handles field ordering, and the locked flag lets you freeze a schema once real entries exist, so old submissions stay comparable. Lock a form before going live in production; edit freely only while it's unlocked and empty.

Field types and validation

Fields are native Filament components, so anything you'd write by hand you can assemble here — including repeaters and heading/layout fields (added in v1.5.0). Validation rules are plain Laravel rule syntax stored per field, so required|email|max:255 behaves exactly as it would in a FormRequest. This is the main appeal: no parallel schema/validation layer to keep in sync.

Options editor for choice fields

For Select/Radio/CheckboxList, prefer key_value (value => label) once you care about stable stored values vs. human labels:

'options_editor' => [
    'RADIO' => 'key_value',
    'SELECT' => 'tags',
    'default' => 'tags',
],

The default tags mode stores label == value, which means renaming an option later desynchronizes historical entries. Choose key_value up front for anything long-lived.

Embedding a form in your own Livewire component

The package exposes its show component, and you should pass blockRedirect when nesting it so submission doesn't navigate away from your page:

@livewire('tapp.filament-form-builder.livewire.filament-form.show', [
    'form' => $test->form,
    'blockRedirect' => true,
])

Reacting to submissions

Two hooks, pick per context:

// Livewire parent component
protected $listeners = ['entrySaved'];

public function entrySaved($entryId) { /* re-resolve the entry */ }
// Laravel event listener
protected $listen = [
    \Tapp\FilamentFormBuilder\Events\EntrySaved::class => [
        \App\Listeners\HandleFormSubmission::class,
    ],
];

The event is the reliable integration point for notifications, CRM pushes, or fan-out to other models. Since v1.26 the Livewire event sends the entry id rather than the model, so re-fetch it in your handler.

Private entries via policy

This is opt-in per form and deliberately not a gate. Put the logic in a policy for FilamentForm with the exact method name:

public function viewEntries(User $user, FilamentForm $form): bool
{
    if (! (bool) $form->private_entries) {
        return true;
    }

    return $user->hasRole('Admin');
}

Then delegate from your FilamentFormUser policy so individual entry view links are gated too:

if ($entry->filamentForm?->private_entries) {
    return $user->can('viewEntries', $entry->filamentForm);
}

This controls the Entries relation manager tab and the Export Selected bulk action.

Multi-tenancy

Configure tenancy before publishing/running migrations, then enable ->tenant(Team::class) on the panel. With tenancy on, queries scope automatically, URLs become /admin/{tenant-slug}/filament-forms, and tenant deletion cascades to forms, fields, and entries. The relationship_name and column overrides matter if your tenant relationship isn't the snake_case default.

Front-end presentation and export

For custom response rendering, override the ShowEntry page class via config rather than forking views, and use the published Blade views as your starting point (the results container carries a fb-form-user-container class for styling hooks). CSV export is a Filament bulk action over selected entries — good for ad-hoc pulls, less good as a scheduled reporting mechanism.

Gotchas and Tips

  • No Packagist release means your lockfile is the source of truth. VCS installs resolve against tags/branches, so pin a specific tag or commit in composer.lock and commit it. ^4.0 can resolve surprisingly if tags are sparse — verify with composer show tapp/filament-form-builder.
  • Docs span two incompatible major lines. README examples are for 4.x/5.x; a lot of the changelog (v1.x: locking, copy action, blockRedirect, repeater/heading fields) describes the Filament 3 line. Don't apply 1.x migration snippets blindly to a 4.x install.
  • Tenancy is a migration-time decision. The migrations inspect config to decide whether to add tenant columns. Turning tenancy on later means hand-writing ALTER TABLE for filament_forms, fields, and entries — plus backfilling. Decide on day one.
  • The private-entries policy fails open. If viewEntries doesn't exist, the package doesn't restrict anything: every user who can view the form sees entries and can export. There's no warning, so add the policy as part of rollout, not after.
  • Method name and signature are load-bearing. It's viewEntries(User $user, FilamentForm $form): bool, called via can() on the owner record — not a gate registration. A typo silently degrades to "no restriction."
  • Tailwind won't style the fields unless you tell it to. Add "./vendor/tapp/**/*.blade.php" to your content array, otherwise dynamically assembled Filament field classes get purged and forms render unstyled. Also make sure the guest panel exists and its ID matches guest-panel-id, or public routes will 500/redirect oddly.
  • Guest access needs both switches. A form must have permit_guest_entries enabled and the guest plugin registered on a real panel; authenticated users get redirected to the app panel, so test both states. php artisan route:list | grep -E 'forms|entries' is the fastest sanity check.
  • Field type is required (enforced since v1.28) — bulk-created or programmatically seeded fields without a type will fail validation. If seeding fields in tests, always set type and rules explicitly.
  • Older versions have known field bugs (radio first-option selection, fixed v1.25; copy action, v1.29/v1.30). With 14 stars and zero dependents, you're an early adopter: pin a recent tag, write a feature test that submits each field type you use, and re-run it on upgrade.
  • Debugging submissions: entries are FilamentFormUser records tied to filament_form_id; inspect the row directly and dump the validated payload in an EntrySaved listener. If a rule isn't firing, confirm the rule string parses standalone before blaming the plugin — it's passed straight into Laravel's validator.
  • Extension points, ranked by stability: config (panel IDs, routes, options editor, custom page classes, custom SetFormPanel middleware) → policy → events. Avoid editing published views as your primary customization path; you'll conflict on the next vendor:publish.
  • Export scale: maatwebsite/excel loads in-process. For thousands of entries, prefer your own queued export or chunked query over the bulk action.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
tunezilla/openapi-test-validation
hapipay/php-client
uretral/laravel-admin
infinitetoken/lumber
zipzoft/laravel-elasticsearch-client
smronju/nativephp-scanner
arm092/laravel-translation
denisgold/laravel-generator
zxg321/laravel-admin
trailscope/trailscope
intragile/laravel-company-lookup
designmynight/laravel-oauth-introspect-middleware
taras-koval/laravel-starter
ssofy/laravel
datalogix/laravel-error-pages
pushinbr/pam-octane
9in/laravel-server
9in/laravel-events
9in/laravel
pushinbr/pam-laravel