Filament v3 Custom Field Plugin: Signature Pad | Mohamed Said        [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://www.msaied.com) [ Home ](https://www.msaied.com) [ Projects ](https://www.msaied.com/projects) [ Articles  ](https://www.msaied.com/articles) [ Certificates ](https://www.msaied.com/certificates) [ Contact ](https://www.msaied.com#contact-section) 

       [  ](https://github.com/EG-Mohamed)       

 [ Home ](https://www.msaied.com) [ Projects ](https://www.msaied.com/projects) [ Articles ](https://www.msaied.com/articles) [ Certificates ](https://www.msaied.com/certificates) [ Contact ](https://www.msaied.com#contact-section) 

  [ home ](https://www.msaied.com)    [ articles ](https://www.msaied.com/articles)    Filament v3 Custom Field Plugins: Building a Reusable Signature Pad Component        On this page       1. [  Why Build a Custom Filament Field Plugin? ](#why-build-a-custom-filament-field-plugin)
2. [  The Component Skeleton ](#the-component-skeleton)
3. [  Alpine.js + Livewire Entanglement ](#alpinejs-livewire-entanglement)
4. [  PHP-Side: Validation and Casting ](#php-side-validation-and-casting)
5. [  Package Auto-Discovery ](#package-auto-discovery)
6. [  Takeaways ](#takeaways)

  ![Filament v3 Custom Field Plugins: Building a Reusable Signature Pad Component](https://cdn.msaied.com/633/6d6839e7007d1cb38f0421594a4557bf.png)

  #filament   #laravel   #livewire   #alpine  

 Filament v3 Custom Field Plugins: Building a Reusable Signature Pad Component 
===============================================================================

     5 Sep 2026      3 min read    ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said  

       Table of contents

1. [  01   Why Build a Custom Filament Field Plugin?  ](#why-build-a-custom-filament-field-plugin)
2. [  02   The Component Skeleton  ](#the-component-skeleton)
3. [  03   Alpine.js + Livewire Entanglement  ](#alpinejs-livewire-entanglement)
4. [  04   PHP-Side: Validation and Casting  ](#php-side-validation-and-casting)
5. [  05   Package Auto-Discovery  ](#package-auto-discovery)
6. [  06   Takeaways  ](#takeaways)

 Why Build a Custom Filament Field Plugin?
-----------------------------------------

Filament ships with a rich field library, but real-world SaaS products inevitably need domain-specific inputs — signature pads, rich colour pickers, geo-coordinate selectors. Understanding how to build one correctly means you can extend Filament without fighting its internals.

This article walks through a **signature pad** field: a canvas-based input that stores a base64 PNG, wired cleanly through Livewire and castable to a value object on the Eloquent model.

---

The Component Skeleton
----------------------

Filament custom fields extend `Filament\Forms\Components\Field`. The minimum surface area is:

```php
namespace Acme\SignaturePad;

use Filament\Forms\Components\Field;

class SignaturePad extends Field
{
    protected string $view = 'signature-pad::signature-pad';

    public function getDefaultState(): mixed
    {
        return null;
    }
}

```

Register the view namespace in your service provider:

```php
public function boot(): void
{
    $this->loadViewsFrom(__DIR__.'/../resources/views', 'signature-pad');
}

```

---

Alpine.js + Livewire Entanglement
---------------------------------

The tricky part is syncing canvas data back to Livewire's state. Filament uses `$wire.entangle` under the hood for its own fields, and you should too.

```blade
{{-- resources/views/signature-pad.blade.php --}}

            Clear

```

The Alpine component:

```javascript
Alpine.data('signaturePad', (state) => ({
    state,
    pad: null,

    init() {
        const canvas = this.$refs.canvas;
        this.pad = new SignaturePad(canvas); // signature_pad npm package

        if (this.state) {
            this.pad.fromDataURL(this.state);
        }

        this.pad.addEventListener('endStroke', () => {
            this.state = this.pad.toDataURL();
        });
    },

    clear() {
        this.pad.clear();
        this.state = null;
    },
}));

```

The `@entangle($getStatePath())` call binds the Alpine `state` property directly to Filament's Livewire component state path — no custom events needed.

---

PHP-Side: Validation and Casting
--------------------------------

Add a validation rule to reject empty submissions when the field is required:

```php
public function getValidationRules(): array
{
    return array_merge(parent::getValidationRules(), [
        $this->getStatePath() => [
            fn () => function (string $attribute, mixed $value, \Closure $fail) {
                if ($this->isRequired() && blank($value)) {
                    $fail('A signature is required.');
                }
                if ($value && !str_starts_with($value, 'data:image/png;base64,')) {
                    $fail('Invalid signature format.');
                }
            },
        ],
    ]);
}

```

On the model, a custom cast keeps the domain layer clean:

```php
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;

class SignatureCast implements CastsAttributes
{
    public function get($model, string $key, mixed $value, array $attributes): ?Signature
    {
        return $value ? new Signature($value) : null;
    }

    public function set($model, string $key, mixed $value, array $attributes): array
    {
        return [$key => $value instanceof Signature ? $value->dataUrl : $value];
    }
}

```

```php
// On the Eloquent model
protected $casts = [
    'signature' => SignatureCast::class,
];

```

---

Package Auto-Discovery
----------------------

For distribution, declare the service provider in `composer.json`:

```json
"extra": {
    "laravel": {
        "providers": [
            "Acme\\SignaturePad\\SignaturePadServiceProvider"
        ]
    }
}

```

Publish assets via the service provider:

```php
public function boot(): void
{
    $this->loadViewsFrom(__DIR__.'/../resources/views', 'signature-pad');

    $this->publishes([
        __DIR__.'/../resources/dist' => public_path('vendor/signature-pad'),
    ], 'signature-pad-assets');
}

```

Users run `php artisan vendor:publish --tag=signature-pad-assets` once, then reference the JS in their Filament panel's `renderHook` or `vite.config.js`.

---

Takeaways
---------

- Extend `Field`, point to a Blade view, and let `@entangle($getStatePath())` handle Livewire sync — no custom events.
- Keep validation inside `getValidationRules()` so Filament's error display works automatically.
- Use a dedicated Eloquent cast to keep raw base64 out of your domain objects.
- Publish JS assets separately from views so consumers can version them independently.
- Declare the service provider in `composer.json` extras for zero-config auto-discovery.

 Found this useful?

          [  ](https://twitter.com/intent/tweet?url=https%3A%2F%2Fwww.msaied.com%2Farticles%2Ffilament-v3-custom-field-plugins-building-a-reusable-signature-pad-component&text=Filament+v3+Custom+Field+Plugins%3A+Building+a+Reusable+Signature+Pad+Component) [  ](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fwww.msaied.com%2Farticles%2Ffilament-v3-custom-field-plugins-building-a-reusable-signature-pad-component) 

 Frequently Asked Questions 
----------------------------

  3 questions  

     Q01  How does @entangle work inside a Filament custom field view?        `@entangle($getStatePath())` compiles to a Livewire JS entangle call using the field's dot-notation state path. Any Alpine property bound to it stays in sync with the Livewire component's state without manual event dispatching. 

      Q02  Can I use this pattern for fields that store structured data instead of a string?        Yes. If your field stores JSON (e.g. coordinates), return an array from `getDefaultState()`, encode/decode in the cast, and ensure Alpine serialises the value to a JSON string before assigning it to the entangled state property. 

      Q03  Do I need to register the Alpine component globally or can it be scoped?        Filament loads Alpine after its own scripts, so you can register via `document.addEventListener('alpine:init', ...)` in a published JS asset, or inline the `Alpine.data` call in a `@push('scripts')` block in your Blade view. 

  Continue reading

 More Articles 
---------------

 [ View all    ](https://www.msaied.com/articles) 

 [ ![Taylor Otwell Disabled GitHub Issues on Most Laravel Open-Source Packages](https://cdn.msaied.com/632/d9612144281f22ce7b18e7ee82a2ea80.png) Laravel Open Source GitHub 

### Taylor Otwell Disabled GitHub Issues on Most Laravel Open-Source Packages

Taylor Otwell has turned off GitHub Issues on most Laravel open-source packages, asking contributors to use a...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 4 Sep 2026     3 min read  

  Read    

 ](https://www.msaied.com/articles/taylor-otwell-disabled-github-issues-on-most-laravel-open-source-packages) [ ![Exclude Vendor and Default Commands in php artisan dev (Laravel 13.30)](https://cdn.msaied.com/631/ba9b50ef4b7355a32c378f404d978b90.png) Laravel Artisan Laravel 13.30 

### Exclude Vendor and Default Commands in php artisan dev (Laravel 13.30)

Laravel 13.30 adds withoutVendorCommands() and withoutDefaultCommands() to the DevCommands class, giving you p...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 4 Sep 2026     3 min read  

  Read    

 ](https://www.msaied.com/articles/exclude-vendor-and-default-commands-in-php-artisan-dev-laravel-1330) [ ![Laravel August 2026 Product Updates: Framework, Cloud, and Forge](https://cdn.msaied.com/630/37bf960d82f877f3063ffe9d11fa3c7b.png) Laravel Laravel Cloud Laravel Forge 

### Laravel August 2026 Product Updates: Framework, Cloud, and Forge

Laravel's August 2026 updates bring read-through filesystems, Turbopuffer semantic search in Scout, rebuilt ma...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 3 Sep 2026     3 min read  

  Read    

 ](https://www.msaied.com/articles/laravel-august-2026-product-updates-framework-cloud-and-forge) 

   [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://www.msaied.com)Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

Explore

- [Home](https://www.msaied.com)
- [Projects](https://www.msaied.com/projects)
- [Articles](https://www.msaied.com/articles)
- [Certificates](https://www.msaied.com/certificates)
- [Contact](https://www.msaied.com#contact-section)

Connect

- [   hello@msaied.com ](mailto:hello@msaied.com)
- [   +20 109 461 9204 ](tel:+201094619204)

© 2026 Mohamed Said. All rights reserved.

 [  ](https://github.com/EG-Mohamed) [  ](https://www.linkedin.com/in/msaiedm/) [  ](https://wa.me/201094619204) [  ](mailto:hello@msaied.com) [  ](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)
