navidcode / filament-page-builder
A visual page builder form field for Filament panels.
Package info
github.com/navidsafavi/filament-pagebuilder
pkg:composer/navidcode/filament-page-builder
Requires
- php: ^8.3
- filament/filament: ^5.0
- livewire/livewire: ^4.0
- spatie/laravel-package-tools: ^1.93
Requires (Dev)
- laravel/pint: ^1.13
- orchestra/testbench: ^11.0
- pestphp/pest: ^5.0
- pestphp/pest-plugin-laravel: ^5.0
README
A visual, extensible page builder form field for Filament 5 and Livewire 4.
Project origin
This package began as an extraction of the Page Builder functionality from Mksine, originally created by Miran Salehi. The Page Builder code was separated into this standalone Filament package so it can be maintained independently and reused outside the original project. Future development in this repository will continue from that foundation and may introduce new components, improvements, and features.
The original and current copyright notices are preserved in LICENSE.md.
Installation
composer require navidcode/filament-page-builder
The package registers its compiled CSS and JavaScript with Filament.
Filament publishes these assets to the application's public directory when its filament:upgrade Composer hook runs during install or update.
If Composer scripts are disabled, publish them manually:
php artisan filament:assets
Register the plugin on the Filament panel:
use NavidCode\PageBuilder\PageBuilderPlugin; return $panel ->plugin(PageBuilderPlugin::make());
Use the field in a Filament schema:
use NavidCode\PageBuilder\Forms\PageBuilderField; PageBuilderField::make('content') ->columnSpanFull();
The model attribute should use Laravel's array cast and be backed by a JSON column.
protected function casts(): array { return [ 'content' => 'array', ]; }
Rendering on the frontend
The builder stores an array of blocks in the model attribute. Render every block through the package's dispatcher view, following the same pattern used by the original Mksine Page Builder:
<div class="page-builder-content"> @foreach ($page->content ?? [] as $block) @include('filament-page-builder::render.block', ['block' => $block]) @endforeach </div>
The dispatcher selects the correct view for each block and recursively renders nested container blocks. Use it instead of including individual component views directly.
Filament loads the published CSS and JavaScript automatically inside panels. To use the package styles when rendering blocks outside Filament, include the published stylesheet in the public frontend layout:
<link rel="stylesheet" href="{{ asset('css/navidcode/filament-page-builder/page-builder.css') }}" >
Tabs, sliders, and accordions use Alpine.js in their rendered markup. If the public layout does not already provide Alpine.js, load Alpine.js there; accordions also require the Alpine Collapse plugin.
Extending the builder
Builder component classes implement BuilderComponentInterface.
Add components or templates to every builder in a panel while registering the plugin:
PageBuilderPlugin::make() ->components([ CustomComponent::class, ]) ->templates([ 'custom-landing' => CustomLandingTemplate::config(), ]);
To use a different set for one field, configure the field directly:
PageBuilderField::make('content') ->extendComponents([ CustomComponent::class, ]) ->excludeComponents([ UnwantedComponent::class, ]) ->templates([ 'custom-landing' => CustomLandingTemplate::config(), ]);
extendComponents() merges custom components with the plugin component set.
If an extended component uses the same type as an existing component, the extended component replaces it for that field.
excludeComponents() removes the listed component classes from the final field set.
Use components() only when the field should replace the complete plugin component set:
PageBuilderField::make('content') ->components([ CustomComponent::class, ]);
The templates() method still replaces the plugin template set for that builder instance.
Omit an override method to inherit its corresponding set from the panel plugin.
Closures are also supported, so the field configuration can depend on the current Filament schema context.
Field-level component configuration controls the editor instance. Register field-only components separately for frontend rendering so the dispatcher can resolve their views without adding them to every editor:
PageBuilderPlugin::make() ->renderComponents([ CustomComponent::class, ]);
The component class declares its output view:
public static function getRenderView(): string { return 'page-builder.render.custom'; }
The custom Blade view receives $data, $blockId, and $children when the block contains children.
For example, create resources/views/page-builder/render/custom.blade.php:
<section> {{ $data['content'] ?? '' }} </section>
renderComponents() only registers frontend view resolution. Use extendComponents() or components() on the field to control which components appear in that editor.
Package development
npm install
npm run build
composer test
npm run build compiles resources/js and resources/css into the package's dist directory.
When developing the package through a Composer path repository, run the following command from the host Laravel application after rebuilding:
php artisan filament:assets
This copies the compiled files into the host application's public/css/navidcode/filament-page-builder and public/js/navidcode/filament-page-builder directories.
Compiled assets in dist are committed so package consumers do not require Node.js.
License
The MIT License. See LICENSE.md.