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 Barcode Field Laravel Package

jeffersongoncalves/filament-barcode-field

Add barcode input to Filament admin panels with a dedicated, scanner-friendly form field for Laravel. It supports validation and clean integration, helping streamline product, inventory, SKU, asset, and order data capture workflows. Easy to configure and fits naturally into existing Filament resourc...

View on GitHub
Deep Wiki
Context7

Getting Started

1. Install with the version constraint that matches your Filament major. This is the first place people trip up — the package version does not track Filament's:

# Filament 3 → package 1.x
composer require jeffersongoncalves/filament-barcode-field:"^1.0"

# Filament 4 → package 2.x
composer require jeffersongoncalves/filament-barcode-field:"^2.0"

# Filament 5 → package 3.x
composer require jeffersongoncalves/filament-barcode-field:"^3.0"

There is no panel plugin to register — BarcodeFieldServiceProvider is auto-discovered and it's a plain form component. If you're used to ->plugin(BarcodeFieldPlugin::make()), don't look for it; it doesn't exist.

2. Look at these two files first. You will spend 90% of your time in src/Forms/Components/BarcodeInput.php (a ~30-line TextInput subclass) and the published config. Read the component before you go to the README — it's small enough that the source is the documentation, and you'll immediately see that icon() is just extraAttributes(['icon' => $icon]).

3. Publish config only if you need to change scan behaviour:

php artisan vendor:publish --tag="filament-barcode-field-config"
php artisan vendor:publish --tag=filament-barcode-field-translations

4. First use case — a product barcode on a resource form. This is the canonical scenario the package is built for (retail/warehouse EAN + Code 128):

use JeffersonGoncalves\Filament\BarcodeField\Forms\Components\BarcodeInput;

public static function form(Schema $schema): Schema
{
    return $schema->components([
        BarcodeInput::make('barcode')
            ->label('Product Barcode')
            ->required()
            ->unique(ignoreRecord: true)
            ->maxLength(64),
    ]);
}

Serve over HTTPS (or localhost) on your first test, otherwise the camera prompt never appears and you'll wrongly assume the package is broken.

Implementation Patterns

Manual entry is the default path; the camera is an enhancement. BarcodeInput extends TextInput, so everything you know about text inputs still applies. Design your forms so a user with a USB/keyboard-wedge scanner gun (which types into the field) or a human typist is fully functional, and treat the camera modal as the third input method. This makes the field usable in CI, on desktops without webcams, and inside your Dusk tests.

Scanner-then-lookup workflow. The highest-value pattern is scan → fill → resolve. Combine live() with a lookup so the operator sees the product name the instant the code lands:

BarcodeInput::make('barcode')
    ->label('Scan item')
    ->live(onBlur: true)          // or ->live(debounce: 300)
    ->afterStateUpdated(function (?string $state, Set $set) {
        $product = Product::where('barcode', $state)->first();
        $set('product_name', $product?->name);
        $set('product_id', $product?->id);
    })
    ->required(),

Keep the resolved name in a disabled TextInput or a Placeholder — operators need visual confirmation that the scan matched.

Enforce checksums yourself. The package reads whatever the camera decodes; it does not validate EAN-13/UPC check digits. Add a rule (or a small custom rule class) so a misread or a hand-typed typo doesn't silently create a bad record:

->rules([
    fn () => function (string $attribute, $value, Closure $fail) {
        if (! app(BarcodeValidator::class)->isValidEan13($value)) {
            $fail('That barcode failed its check-digit test — rescan.');
        }
    },
])

Restrict symbologies globally, per deployment. config('filament-barcode-field.formats') maps to html5-qrcode's Html5QrcodeSupportedFormats enum. A retail app that only stocks EAN-13/EAN-8 should run:

'formats' => ['EAN_13', 'EAN_8'],

Fewer formats = faster lock-on and fewer false positives. Treat this as an environment/config concern (e.g. per-tenant config) rather than something you flip casually.

Tune the scan box for your stock. 1D barcodes are wide and short, and the library needs the code to fit inside the reader box. If scanners struggle on long Code 128 labels, widen scanner.width relative to scanner.height and raise scanner.fps (default 10) for handheld motion. Defaults are 300×150 with a 600×600 reader — fine for EAN on a phone, cramped for wide labels.

Display and search. Pair the input with a matching table column so records are scannable back out:

TextColumn::make('barcode')
    ->searchable()
    ->copyable()
    ->fontFamily(FontFamily::Mono)
    ->icon('heroicon-o-qr-code'),

Add a ->searchable() on the column and an index on the DB column — operators will paste codes into the global search.

i18n comes free but needs a label. The auto-placeholder is built from your label via the translation key filament-barcode-field::barcode-field.fields.placeholder. With 17 locales shipped in 1.1.0, non-English panels get sensible placeholders without any work — provided you call ->label('...').

Gotchas and Tips

The version matrix is the #1 support ticket. ^3.0 is the Filament 5 release, not the third iteration of a Filament 3 package. Composer will happily resolve ^1.0 on a Filament 5 app and you'll get a component that renders into a view API that no longer exists. Pin the constraint in composer.json and add a comment.

HTTPS is mandatory for getUserMedia. No amount of config will make the camera work over plain HTTP on a LAN IP. If your warehouse terminal runs on http://192.168.x.x, use a self-signed cert, a tunnel, or accept keyboard-wedge scanners only.

The JS is loaded from a CDN (unpkg, html5-qrcode 2.3.8). Two consequences: a strict CSP needs unpkg.com in script-src, and air-gapped/on-prem deployments get no scanner at all. Fix by self-hosting the file and overriding asset_js:

'asset_js' => asset('vendor/html5-qrcode.min.js'),

Pin the version deliberately — the config ships an exact @2.3.8 for a reason; don't point it at @latest.

->icon() is not Filament's icon API. It stashes the name in extraAttributes(['icon' => ...]), so the icon only renders because the package's Blade view knows to look for it. It won't behave like TextInput::prefixIcon(), it won't inherit Filament's icon sizing/colour conventions, and any custom view you swap in must re-implement it. If you want a standard prefix icon, use ->prefixIcon() (inherited from TextInput) instead and leave icon() alone.

Placeholders degrade badly without a label. The setUp() does strtolower($component->getLabel()). Call ->label() on every instance, or you'll get a placeholder reading "enter barcode" with an empty or awkward interpolation — and strtolower() on non-Latin labels is a no-op at best.

Formats and dimensions are global-only. There is no ->formats() or ->scannerWidth() fluent API. If one form scans retail EANs and another scans asset-tag Code 39, you cannot express that in config. Options: publish the config and set the union of formats (slower, more false positives), or subclass the component and push your own values into the view's Alpine data. Budget for the subclass if you have mixed use cases.

Livewire re-renders can orphan the camera stream. The scanner is Alpine + a modal; if the component is re-rendered or removed (repeater row deleted, modal closed, step wizard advance) while the camera is open, you can leave the light on and the Html5Qrcode instance alive. Guard with $wire.on('...') cleanup or defer the component until the tab is active. Test explicitly inside modals and repeaters — that's where it breaks.

No validation, no normalisation, no trimming. The component hands you whatever the decoder returned. Trim whitespace, uppercase Code 39, and strip GS1 application identifiers before persisting. Do it in ->dehydrateStateUsing() rather than in your save handler so it applies to programmatic fill() too.

Debugging checklist, in order: browser console for Html5Qrcode is not defined (asset/CSP problem) → php artisan filament:assets then php artisan optimize:clear (stale Filament asset manifest) → php artisan config:clear (you edited the config and forgot the cache) → check formats includes your symbology → check the scan box aspect ratio.

Vendor risk is real but bounded. Four stars and zero dependents means don't expect upstream fixes on your schedule. The mitigation is cheap: the whole surface area is one form class plus one Blade view, with hasViews() registered, so you can publish the views, copy BarcodeInput into App\Forms\Components, and own it. Before adopting, verify the view publish tag exists (php artisan vendor:publish and look for filament-barcode-field-views) — if it doesn't, fork rather than monkey-patch.

CI and tests will never exercise the camera. Assert on state instead: fillForm(['barcode' => '4006381333931'])->assertFormSet(...) and unit-test your checksum rule separately. Anything relying on the modal is manual QA.

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.
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox