chengkangzai/filament-qrcode-scanner-html5

A Filament form action for scanning barcodes and QR codes using the device camera with html5-qrcode library

Installs: 433

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/chengkangzai/filament-qrcode-scanner-html5

v2.0.0 2026-02-04 17:26 UTC

This package is auto-updated.

Last update: 2026-02-04 17:28:37 UTC


README

Latest Version on Packagist Tests Total Downloads License

A Filament form action for scanning barcodes and QR codes using the device camera. Built with the html5-qrcode library.

Features

  • Three-tier architecture: Use as Filament action, standalone Livewire component, or pure Alpine.js
  • Scan QR codes and various barcode formats (Code128, Code39, EAN-13, UPC-A, ITF, and more)
  • Works on mobile and desktop devices with camera access
  • Configurable scanner options: fps, qrbox, aspect ratio, camera facing mode
  • Automatic camera switching (front/back) or force specific camera
  • Transform scanned values with PHP closures or JavaScript functions
  • Header action support for standalone scanning (e.g., attendance check-in)
  • Fully customizable labels and error messages
  • Dark mode support
  • Accessible with ARIA labels

Requirements

  • PHP 8.2+
  • Laravel 11.28+
  • Filament 4.x
  • Livewire 3.x

Installation

Install the package via Composer:

composer require chengkangzai/filament-qrcode-scanner-html5

The package will auto-register its service provider.

Upgrading from v1.x

v2.0 requires Filament 4, PHP 8.2+, and Laravel 11.28+.

For Filament 3 support, use v1.x:

composer require chengkangzai/filament-qrcode-scanner-html5 "^1.3"

See UPGRADE.md for detailed migration instructions.

Usage

Basic Usage

Add the BarcodeScannerAction as a suffix action to any text input:

use CCK\FilamentQrcodeScannerHtml5\BarcodeScannerAction;

TextInput::make('barcode')
    ->suffixAction(BarcodeScannerAction::make())

Limit Supported Formats

Restrict scanning to specific barcode formats:

use CCK\FilamentQrcodeScannerHtml5\BarcodeScannerAction;
use CCK\FilamentQrcodeScannerHtml5\Enums\BarcodeFormat;

TextInput::make('product_code')
    ->suffixAction(
        BarcodeScannerAction::make()
            ->supportedFormats([
                BarcodeFormat::QRCode,
                BarcodeFormat::Code128,
                BarcodeFormat::Ean13,
            ])
    )

Transform Scanned Values (PHP)

Use a PHP closure to transform the scanned value server-side:

use CCK\FilamentQrcodeScannerHtml5\BarcodeScannerAction;
use CCK\FilamentQrcodeScannerHtml5\Enums\BarcodeFormat;

TextInput::make('barcode')
    ->suffixAction(
        BarcodeScannerAction::make()
            ->modifyStateUsing(fn (string $value, ?BarcodeFormat $format) =>
                // Strip leading zeros from ITF barcodes
                $format === BarcodeFormat::ITF
                    ? ltrim($value, '0')
                    : $value
            )
    )

Transform Scanned Values (JavaScript)

Use a JavaScript function to transform the scanned value client-side:

use CCK\FilamentQrcodeScannerHtml5\BarcodeScannerAction;

TextInput::make('barcode')
    ->suffixAction(
        BarcodeScannerAction::make()
            ->modifyStateUsingJs("(value, formatId) => value.replace(/^0+/, '')")
    )

Format IDs for JavaScript: QR=0, PDF417=10, Code39=4, Code128=6, DataMatrix=12, ITF=8

Customize Labels and Messages

use CCK\FilamentQrcodeScannerHtml5\BarcodeScannerAction;

TextInput::make('barcode')
    ->suffixAction(
        BarcodeScannerAction::make()
            ->switchCameraLabel('Toggle Camera')
            ->cameraUnavailableMessage('No camera detected on this device.')
            ->permissionDeniedMessage('Please allow camera access in your browser settings.')
    )

Header Action (Standalone Scanning)

Use BarcodeScannerHeaderAction for standalone scanning without a form field, such as attendance check-in or inventory lookup:

use CCK\FilamentQrcodeScannerHtml5\BarcodeScannerHeaderAction;
use CCK\FilamentQrcodeScannerHtml5\Enums\BarcodeFormat;
use Filament\Notifications\Notification;

// In your Filament Resource page (ListRecords, ViewRecord, etc.)
protected function getHeaderActions(): array
{
    return [
        BarcodeScannerHeaderAction::make()
            ->label('Scan Attendance')
            ->afterScan(function (string $value, ?BarcodeFormat $format) {
                $user = User::where('qr_code', $value)->first();

                if (! $user) {
                    Notification::make()
                        ->title('User not found')
                        ->danger()
                        ->send();

                    return null; // Just close the modal
                }

                // Mark attendance
                $user->attendances()->create(['checked_in_at' => now()]);

                // Redirect to user page
                return redirect()->route('filament.admin.resources.users.view', $user);
            }),
    ];
}

The afterScan callback can return:

  • redirect('/url') or redirect()->route('name', $params) - Redirect to a URL
  • '/url' - String URL to redirect
  • null - Just close the modal (useful after showing a notification)

Scanner Configuration Options

Configure scanner behavior with these options (available on all actions):

use CCK\FilamentQrcodeScannerHtml5\BarcodeScannerAction;
use CCK\FilamentQrcodeScannerHtml5\Enums\BarcodeFormat;

TextInput::make('barcode')
    ->suffixAction(
        BarcodeScannerAction::make()
            ->fps(15)                          // Frames per second (1-30, default: 10)
            ->qrbox(250)                       // Square focus box (250x250)
            ->qrbox(300, 200)                  // Rectangle focus box (300x200)
            ->aspectRatio(1.777778)            // Camera aspect ratio (16:9)
            ->preferBackCamera()               // Force back/environment camera
            ->preferFrontCamera()              // Force front/user camera
            ->facingMode('environment')        // Alternative: 'user' or 'environment'
            ->supportedFormats([...])          // Limit barcode formats
            ->iconOnly()                       // Show only icon (no text label)
            ->controlPosition('center')        // Align controls: 'left', 'center', 'right'
            ->hideCameraName()                 // Hide camera name label
    )

Configuration Options Reference

Option Type Default Description
fps(int) 1-30 10 Frames per second for scanning
qrbox(int, ?int) pixels null Focus box dimensions (width, height)
aspectRatio(float) ratio null Camera feed aspect ratio
facingMode(string) 'user'|'environment' null Camera facing mode
preferBackCamera() - - Alias for facingMode('environment')
preferFrontCamera() - - Alias for facingMode('user')
controlButtonStyle(string) 'icon'|'icon-text' 'icon-text' Switch camera button display style
iconOnly() - - Convenience for controlButtonStyle('icon')
iconWithText() - - Convenience for controlButtonStyle('icon-text')
controlPosition(string) 'left'|'center'|'right' 'left' Controls alignment
showCameraName(bool) boolean true Show/hide camera name label
hideCameraName() - - Convenience for showCameraName(false)

Standalone Usage (Without Filament)

This package can be used outside of Filament panels for custom integrations.

Livewire Component

Use the standalone Livewire component in any Laravel application:

// In your Livewire component
use CCK\FilamentQrcodeScannerHtml5\Enums\BarcodeFormat;

class CheckInPage extends Component
{
    public $scannedValue = null;

    public function handleScan($value, $formatId)
    {
        $this->scannedValue = $value;
        $format = BarcodeFormat::fromHtml5QrcodeFormat($formatId);

        // Your custom logic here
        $this->processCheckIn($value);
    }

    public function render()
    {
        return view('livewire.check-in-page');
    }
}
{{-- In your blade view --}}
<div>
    <livewire:barcode-scanner
        wire:key="scanner"
        @barcode-scanned.window="$wire.handleScan($event.detail.value, $event.detail.formatId)"
    />

    @if($scannedValue)
        <p>Scanned: {{ $scannedValue }}</p>
    @endif
</div>

Pure Alpine.js Component

Use the base component without any framework dependencies:

<x-filament-qrcode-scanner-html5::barcode-scanner
    id="my-scanner"
    :config="[
        'fps' => 15,
        'qrbox' => ['width' => 250, 'height' => 250],
        'aspectRatio' => 1.777778,
        'facingMode' => 'environment'
    ]"
    :supported-formats="[0, 6, 8]"  {{-- QR Code, Code128, ITF --}}
    :labels="[
        'switchCamera' => 'Toggle Camera',
        'cameraUnavailable' => 'No camera found',
        'permissionDenied' => 'Camera access denied'
    ]"
    @barcode-scanned.window="handleScan($event.detail)"
    @barcode-scanner-error.window="handleError($event.detail)"
/>

<script>
function handleScan(detail) {
    console.log('Scanned value:', detail.value);
    console.log('Format:', detail.formatName);
    console.log('Format ID:', detail.formatId);
    console.log('Timestamp:', detail.timestamp);
    console.log('Scanner ID:', detail.scannerId);
}

function handleError(detail) {
    console.error('Scanner error:', detail.error);
    console.log('Error type:', detail.errorType);
}
</script>

Browser Events

The Alpine.js component emits these browser events:

Event Detail Properties Description
barcode-scanned value, formatId, formatName, scannerId, timestamp Barcode successfully scanned
barcode-scanner-error error, errorType, scannerId, timestamp Scanner error occurred
barcode-scanner-ready cameraCount, currentCamera, scannerId, timestamp Scanner initialized
barcode-scanner-stopped scannerId, timestamp Scanner stopped

Error types: 'not_supported', 'overconstrained', 'permission_denied', 'camera_unavailable', 'unknown'

Supported Barcode Formats

Format Enum Value Format ID
QR Code BarcodeFormat::QRCode 0
Aztec BarcodeFormat::Aztec 1
Codabar BarcodeFormat::Codabar 2
Code 39 BarcodeFormat::Code39 4
Code 93 BarcodeFormat::Code93 5
Code 128 BarcodeFormat::Code128 6
ITF BarcodeFormat::ITF 8
EAN-13 BarcodeFormat::Ean13 9
PDF417 BarcodeFormat::Pdf417 10
EAN-8 BarcodeFormat::Ean8 11
Data Matrix BarcodeFormat::DataMatrix 12
UPC-A BarcodeFormat::UpcA 14
UPC-E BarcodeFormat::UpcE 15

Publishing Views

If you need to customize the scanner modal view:

php artisan vendor:publish --tag=filament-qrcode-scanner-html5-views

Changelog

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

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Security

If you discover any security-related issues, please email pycck@hotmail.com instead of using the issue tracker.

Credits

License

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