| Install | |
|---|---|
composer require chengkangzai/filament-qrcode-scanner-html5 |
|
| Latest Version: | v2.1.0 |
| PHP: | ^8.2 |
| License: | MIT |
| Last Updated: | Mar 1, 2026 |
| Links: | GitHub · Packagist |
A Filament form action for scanning barcodes and QR codes using the device camera. Built with the html5-qrcode library.
Install the package via Composer:
composer require chengkangzai/filament-qrcode-scanner-html5
The package will auto-register its service provider.
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.
Add the BarcodeScannerAction as a suffix action to any text input:
use CCK\FilamentQrcodeScannerHtml5\BarcodeScannerAction;
TextInput::make('barcode')
->suffixAction(BarcodeScannerAction::make())
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,
])
)
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
)
)
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
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.')
)
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 redirectnull - Just close the modal (useful after showing a notification)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
)
| 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) |
This package can be used outside of Filament panels for custom integrations.
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>
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>
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'
| 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 |
If you need to customize the scanner modal view:
php artisan vendor:publish --tag=filament-qrcode-scanner-html5-views
Please see CHANGELOG for more information on what has changed recently.
Contributions are welcome! Please feel free to submit a Pull Request.
If you discover any security-related issues, please email pycck@hotmail.com instead of using the issue tracker.
The MIT License (MIT). Please see License File for more information.