Search by

mmuqiitf / filament-qr-code

mmuqiitf

A powerful, modern QR code package for Filament v5 supporting generation, camera reading, sequential fields, and hardware scanners.

Package info

github.com/mmuqiitf/filament-qr-code

pkg:composer/mmuqiitf/filament-qr-code

Statistics

Installs: 6

Dependents: 0

Suggesters: 0

Stars: 2

Open Issues: 0

v0.1.1 2026-10-10 11:52 UTC

This package is auto-updated.

Last update: 2026-10-10 11:53:01 UTC


README

Filament QR Code banner

Latest Version on Packagist GitHub Tests Action Status PHPStan Level 9 Total Downloads

A powerful, modern QR code package designed exclusively for Filament v5 and Laravel 11 / 12 / 13.

Features:

  • 📷 Interactive Camera Scanner: Real-time camera stream, rear-camera prioritization with remembered choice, responsive decode box synced to the on-screen reticle, and image upload fallback with zero CDN latency.
  • 🔗 Sequential Scanning: One shared camera feed walks through a multi-field checklist (QrScanSequence), with editable or locked steps.
  • 🔫 Hardware Scanner Support: Native burst keystroke detection (<50ms) that absorbs trailing Enter keys to prevent premature form submissions.
  • 📦 Batch Collector (Repeaters & Lists): Continuous scanning mode with duplicate protection and sound/haptic confirmation for rapid inventory logging.
  • 🎨 Full QR Generator Suite: Generate SVG & PNG QR codes with captions/text overlays, logo embedding, and schema components for Forms, Tables, Infolists, and Actions.
  • 🔊 Sensory Confirmation: Instant zero-latency synthesized Web Audio tone and mobile haptic feedback, pitch and duration tunable per component.

Requirements

  • PHP ^8.2, Laravel 11/12/13, Filament v5.
  • PNG generation needs gd or imagick plus system fonts (fonts-dejavu-core on Debian).
  • Camera scanning needs a secure context (https or localhost).
  • The camera bundle (html5-qrcode) is compiled into resources/dist/ — no CDN. After changing anything under resources/js or resources/css, rebuild with npm run build (CI fails when committed dist/ is stale).

How it works

  • Camera scanning runs fully in the browser: a modal viewfinder streams the camera through the bundled decoder. The decoder chunk lazy-loads on first camera use; pages that only render QR images never fetch it.
  • Hardware scanners emulate keyboards: they burst keystrokes in a few dozen milliseconds and end with a terminator key (Enter/Tab). The interceptor buffers bursts, swallows the terminator so forms don't submit, and routes the value to the active field.
  • Sequences and collectors write through $wire.set into your Livewire form state, so scanned values behave like typed input (validation and reactivity included). Camera DOM lives under wire:ignore so Livewire morphs never kill a running feed.
  • Generation is server-side: renders are cached in-process plus in the Laravel cache, so repeated values encode once. Table modal previews load lazily through a signed image route instead of embedding a data-URI per row.

Installation

You can install the package via composer:

composer require mmuqiitf/filament-qr-code

Publish the configuration file (optional):

php artisan vendor:publish --tag="filament-qr-code-config"

Register the plugin in your Filament Panel Provider (optional — JS/CSS auto-register globally via the service provider, so existing installs that already call ->plugin() keep working with no duplicate tags):

use Mmuqiitf\FilamentQrCode\FilamentQrCodePlugin;

public function panel(Panel $panel): Panel
{
    return $panel
        // ...
        ->plugin(FilamentQrCodePlugin::make());
}

The camera decoder (html5-qrcode, ~375K) is split into a lazy chunk: the global bundle is ~20K and the decoder downloads once, on first camera use. Pages that only render QR images never fetch it.

Symbologies

Pass BarcodeFormat cases (or raw strings) via ->formats([...]) on every camera component. Supported: QrCode, Aztec, DataMatrix, Maxicode, Codabar, Code39, Code93, Code128, Itf, Ean13, Ean8, UpcA, UpcE. Filtering formats speeds up decoding and cuts false positives — always set it when you know what you scan. One-dimensional codes automatically get a wide decode band instead of a square.

Quick start

use Mmuqiitf\FilamentQrCode\Forms\Components\QrScanner;

QrScanner::make('sku')->label('SKU'),

Camera modal, upload fallback, and hardware-scanner capture all work out of the box. Add ->formats([...]) when you know the symbology — the guides below are upgrades to this.

Usage

Which component do I need?

Job Use Why not the others
One input scanned by camera, upload, typing, or gun QrScanner Sequence/collector add moving parts a single field doesn't need.
Cashier/POS gun, no camera UI QrHardwareScannerListener + one funnel method QrScanner's field listener would double-handle the same burst.
One camera walking many fields in order QrScanSequence Chained nextField() hops between separate cameras; the sequence shares one feed.
Two fields, hand focus from one to the next QrScanner::nextField() A sequence is overkill without a shared checklist.
Many scans into one list (stocktake, receiving) QrCollector / QrCollectAction Sequences map one scan to one field; collectors append.
Show a QR (form, table, infolist, download) QrCodeDisplay / QrColumn / QrEntry / DownloadQrAction Scanner components capture; these only render.
Many QRs out at once (labels, handover) DownloadQrBulkAction + print sheet Single downloads don't scale past a handful of rows.

Basic implementation

Single field with camera, upload fallback, and hardware-scanner capture:

use Mmuqiitf\FilamentQrCode\Forms\Components\QrScanner;
use Mmuqiitf\FilamentQrCode\Enums\BarcodeFormat;

QrScanner::make('sku')
    ->formats([BarcodeFormat::QrCode, BarcodeFormat::Code128])
    ->sound(true);

Hands-free station — one gun driving the whole page, no camera UI:

use Mmuqiitf\FilamentQrCode\Forms\Components\QrHardwareScannerListener;

QrHardwareScannerListener::make(['sku', 'quantity'])
    ->autoFocusNext(true);

One camera walking many fields in order:

use Mmuqiitf\FilamentQrCode\Forms\Components\QrScanSequence;

QrScanSequence::make(['batch_number', 'serial_number'])
    ->statePath('sequence')
    ->formats([BarcodeFormat::QrCode]);

Continuous batch scanning into a list:

use Mmuqiitf\FilamentQrCode\Forms\Components\QrCollector;

QrCollector::make('scanned_items')
    ->allowDuplicates(false);

Render a QR from record data:

use Mmuqiitf\FilamentQrCode\Forms\Components\QrCodeDisplay;
use Mmuqiitf\FilamentQrCode\Tables\Columns\QrColumn;

QrCodeDisplay::make('qr')
    ->data(fn ($record) => $record?->uuid)
    ->size(200);

QrColumn::make('sku')
    ->thumbnailSize(48)
    ->previewable();

Cashier/POS flow with a handheld gun: see the POS tutorial.

Advanced implementation

Tune defaults globally (php artisan vendor:publish --tag="filament-qr-code-config" → config/qr-code.php), or per component — component options always win:

QrScanner::make('sku')
    ->fps(25)
    ->qrbox(250)
    ->hardwareScanner(terminators: ['Enter', 'Tab'], minBarcodeLength: 2)
    ->beepFrequency(880)
    ->beepDuration(80);

Normalize and reject live scans (scanFormat() / onScan() never run on live scans — they are programmatic-only):

QrScanner::make('sku')
    ->normalizeUsing(fn ($rawValue) => strtoupper(trim((string) $rawValue)))
    ->rejectWhen(fn ($state) => strlen((string) $state) < 3, 'Barcode too short.');

Audit server-observed scans (live scans stay client-side until they reach the server):

use Illuminate\Support\Facades\Event;
use Mmuqiitf\FilamentQrCode\Events\QrCodeScanned;

// config/qr-code.php
'audit' => ['enabled' => true, 'channel' => null],

// or listen yourself:
Event::listen(QrCodeScanned::class, fn ($event) => logger()->info("Scanned {$event->code}"));

Build payloads without hand-escaping:

use Mmuqiitf\FilamentQrCode\Support\QrPayload;

QrPayload::wifi('Shop Floor', 'secret-1');

UI strings live under filament-qr-code::ui (publish with --tag="filament-qr-code-translations"); wrap QR images in .filament-qr-label-sheet / .filament-qr-label for printable shelf labels. Full tables, events, and extension hooks: Reference.

Full guides

  • Scanning — camera field, station listener, sequences, focus handoff, POS tutorial.
  • Batch collecting — continuous inventory scanning in repeaters and tables.
  • Generating — display components, download actions, facade, payloads.
  • Reference — configuration, events, customizing, extending.

Troubleshooting

Run the built-in checks first:

php artisan qr-code:doctor
Symptom Likely cause Fix
Camera modal says no devices / access denied Page served over plain http (not localhost) Serve via https or test on localhost; browsers block cameras in insecure contexts.
Camera modal empty on first open Permission not granted yet, labels unavailable Grant permission, reopen; the remembered localStorage choice wins afterwards.
Stale scanner UI after updating the package Committed dist/ rebuilt but host serving old assets npm run build in the package, then php artisan filament:assets in the host app.
PNG looks wrong / text overlay is blocky Missing GD/Imagick or system fonts Install gd or imagick plus fonts-dejavu-core; the service falls back to GD bitmap fonts otherwise.
Sequence submit misses scanned values statePathPrefix() doesn't match the schema statePath() Set both to the same prefix, or give the sequence ->statePath() and read via mergeSequenceState(). A banner warns in the UI when they differ.
Same burst handled twice Field QrScanner listener + page QrHardwareScannerListener both active Keep the global listener; field handlers stand down automatically (or ->suppressWhenGlobalListener(false)).
Typed text becomes a "scan" minBarcodeLength too low for a keyboard-heavy form Raise minBarcodeLength to 4–6 on that component.
Table page is slow with many QRs Eager modal data-URIs per row Keep ->lazyModal() (default) and the persistent cache enabled; tune generator.cache_ttl.

Reporting issues

  1. Run php artisan qr-code:doctor and include its output.
  2. Include your PHP / Laravel / Filament versions (php -v, composer show laravel/framework filament/filament), plus for camera issues the browser and whether the page is served over https/localhost, and for gun issues the scanner model and its suffix keys.
  3. Describe expected vs actual, with a minimal schema snippet that reproduces it.

Security vulnerabilities are handled privately — see Security Vulnerabilities, not public issues.

Contributing

PRs welcome! See CONTRIBUTING.md for the test suite, static analysis, code style, and frontend build workflow.

Changelog

Please see CHANGELOG.md for more information on what has changed recently.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

Credits

License

The MIT License (MIT). Please see License File for more information.