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

Nova Signature Laravel Package

eom-plus/nova-signature

A Laravel Nova field for capturing and storing handwritten signatures. Adds a signature pad to Nova forms, saves signature images or data with your models, and displays signatures in resource views for simple e-signature capture in admin panels.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the field like any other Nova package:

composer require eom-plus/nova-signature

Nova discovers the service provider automatically. You need a column to hold the drawn signature — the field typically persists the canvas output as a base64 data URL, so give it room:

Schema::table('contracts', function (Blueprint $table) {
    $table->longText('signature')->nullable();
});

Attach it to a resource:

use EomPlus\NovaSignature\Signature;

public function fields(Request $request)
{
    return [
        ID::make()->sortable(),
        Text::make('Title'),
        Signature::make('Signature'),
    ];
}

Open a record, draw in the pad, and save. That is the first end-to-end use case: capturing a wet-style signature on a consent form, delivery note, or contract and persisting it to a single column.

Where to look first

  1. src/Signature.php — the field class. This tells you the real API: whether it supports ->disk()/->path()/->storeAs(), canvas sizing modifiers, and how fill() and resolve() treat the stored value.
  2. resources/js/components/ (or dist/) — the Vue component. Confirm which signature-pad library and which Vue major version it was built against.
  3. README.md — usually shows the storage-as-file example; copy that rather than inventing your own.

Implementation Patterns

Raw base64 in a column (simplest). Drop Signature::make('Signature') on the resource and store the data URL directly. Rendering on the detail view is free if the field ships a display component; otherwise use ->displayUsing(fn ($value) => $value ? 'Signed' : 'Unsigned') and render the image yourself.

Store as a file. If the field exposes ->disk('public')->path('signatures') or ->storeAs(...), prefer it — the column then holds a path and your database stays small. Pair it with an accessor or ->thumbnail() for index views. If the field only emits base64, decode it in a model observer instead:

static::saved(function (Contract $contract) {
    if (str_starts_with($contract->signature ?? '', 'data:image')) {
        $path = 'signatures/'.$contract->id.'.png';
        Storage::disk('public')->put(
            $path,
            base64_decode(explode(',', $contract->signature, 2)[1])
        );
        $contract->forceFill(['signature' => $path])->saveQuietly();
    }
});

Gate the field on workflow state. Signature capture belongs to a specific step, not the whole record lifecycle:

Signature::make('Signature')
    ->canSee(fn () => $this->status === 'awaiting_signature')
    ->rules('required'),

Multiple signers. Two fields on the same resource (customer_signature, witness_signature) is cleaner than a polymorphic signatures table for straightforward forms. If signatures are versioned or audited, keep them in a separate signatures table and use the field only on the capture screen.

Pair with an Action. A common pattern is a "Sign" action whose modal shows the field, so signatures are appended without a full resource edit. Verify the canvas mounts — hidden-at-mount modals are the usual failure point (see Gotchas).

Customize the component. Override the Vue component via Nova::script() or by extending the field and setting $component, so you can add a "clear" button, change pen color, or embed a timestamp overlay.

Gotchas and Tips

  • Column size. A 600×200 PNG signature is routinely 10–50 KB of base64. string(255) will silently truncate. Use longText/mediumText.

  • Empty pads still submit a value. Signature Pad produces a blank (often fully transparent) data URL even when nothing was drawn. ->rules('required') passes because the string is non-empty. Add a custom rule that rejects the known-empty payload or checks decoded byte length:

    Rule::notIn(['data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...']) // blank canvas
    

    More robustly, validate on the server that the trimmed payload exceeds a small threshold.

  • Retina / canvas scaling. If you set CSS width/height without setting the canvas attributes, strokes land offset from the cursor on high-DPI screens. Set explicit pixel dimensions via the field's sizing modifiers and let CSS scale.

  • Modal and tab mounting. Inside Nova action modals or collapsed tabs the canvas can mount at zero width, producing an empty or squashed signature. Force a resize() on show, or render the field on a dedicated step.

  • Nova version risk. The last release is January 2024, stars and dependents are negligible, and Nova's asset pipeline changed across 4.x and 5.x. Test on your exact Nova/Vue version; if the component fails to register, you will usually see an unregistered-component warning in the browser console rather than a server error.

  • Hydration semantics differ by storage mode. With base64 storage the field hydrates the full data URL; with file storage it hydrates a path. Watch out for a resolveUsing that assumes one format — mixing both during a migration will produce broken <img> tags.

  • Payload bloat. Base64 signatures are heavy in JSON index responses. Always ->hideFromIndex() (or use a thumbnail) and avoid loading the field in list endpoints.

  • Debugging the saved value. Inspect the Nova update request in the Network tab to see exactly what the hidden input contains. Then confirm the model actually persisted it ($model->getRawOriginal('signature')); a mismatch usually means fill() is dropping the key or a saving observer is overwriting it.

  • Config and cleanup. If the package ships a config tag, publish it (php artisan vendor:publish --tag=nova-signature-config) to change defaults like pen color or canvas size. When storing to disk, add cleanup to the model's deleting event so orphaned signature files don't accumulate.

  • Extension points. Extend the field class, override the $component property, and register a replacement component through a small Nova asset package — this is the cleanest way to add features without forking. Keep the fork's Vue build script (npm run dev/prod) working locally so you can rebuild dist/ after changes.

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.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect