Skip to main content
Scan a product, ticket or inventory label directly into your form. BarcodeScannerField combines the FLEX text input with a camera scanner that fills its viewing surface, floating controls and an optional confirmation sound.

Camera and manual entry

Use the camera, type a code or connect a keyboard-style barcode reader.

Validate before saving

Restrict formats, verify EAN/UPC checksums and add your own business rules.

Start with one field

The default value is a trimmed string, or null when empty. Save it in a string column. No media table or storage disk is required for scanning. For long QR payloads use a text column, or set barcodeRule('max:255') when your database column is limited to 255 characters. The scan button opens a camera surface with a close button and a framing guide. Camera switching appears when multiple video inputs are available; the torch appears when the active camera reports support. A successful scan fills the field and closes the scanner. Enable continuous() to keep it open.

Supported formats

All 10 formats listed above are enabled by default; this does not mean every barcode symbology that exists. formats() and its alias supportedFormats() accept enum cases or the listed slugs. An empty list or an unknown format is a configuration error.
modalHeading() sets the scanner’s accessible name; there is no visible header over the camera.

All formats, a subset or dynamic selection

The whitelist configures the decoder and is enforced again on the server. Prefer a smaller set when you know which labels your workflow uses.

Your own company codes

Use a supported symbology to carry your own data, then validate its content. For example, encode FLEX-A1B2C3D4 in a QR code:
barcodeRule() validates on form submission. It does not install a camera decoder or add a name to BarcodeFormat. A new physical symbology outside the supported list needs a decoder implementation; passing an invented format name is rejected. Do not treat the camera’s success sound as confirmation that your server-side business rule has passed.

Store the detected format

Use a JSON column and an Eloquent array cast for structured values:
A camera scan stores:
Manual entry stores format: null. Changing the manually entered value clears its previous detected format. A plain string loaded into a structured field also receives format: null.
The camera identifies a physical barcode format. Text entered by hand has no physical symbology to inspect. Server validation checks value patterns and any supplied format, but format metadata is not proof that a camera was used. Restrict formats and add application rules for values that require stronger checks.

Validation and business rules

Validation runs on the server before normal form state is saved. Invalid state types, unknown keys, invalid format metadata, nested values, null bytes and values over 4,096 UTF-8 bytes are rejected. A scalar field rejects structured payloads. validateChecksum() verifies EAN-13, EAN-8, UPC-A and expanded UPC-E checksums. UPC-E needs its check digit: a six-digit body alone cannot pass checksum validation. When a numeric value matches an enabled EAN/UPC format, adding the broad QR format does not bypass checksum verification for manual entry.
Use barcodeRule() for an additional Laravel rule string or a callback. The callback receives the extracted string in both storage modes.
Manual typing remains editable while validation is handled on submission. Codes recognized by the camera are checked before replacing the current value.

Continuous scanning

Each accepted scan replaces the field’s value. Continuous mode does not accumulate an array of scans. A code that stays in view is accepted once. The same code can be accepted again after it has left view for at least scanDelay(); a different code can be accepted immediately. You can listen for the bubbling barcode-scanned event to maintain your own inventory workflow. Its detail contains value, format, engine and statePath.

Preview before saving

A recognized code plays one sound, freezes a local camera frame and releases the camera. Save code commits the value; Scan again discards the pending result and restarts the camera. Closing the preview keeps the previous field value unchanged. The frame is a temporary in-memory preview: it is not uploaded or stored. Confirmation is off by default. With continuous()->confirmScan(), saving starts the next scan; a code that remains visible is not repeatedly accepted. Automatic form submission happens only after confirmation.

Camera, performance and privacy

The scanner uses the native detector when it supports every configured format. Otherwise it loads the bundled ZXing decoder when scanning starts. Rendering a field does not request camera permission or load ZXing. Native support is checked through BarcodeDetector.getSupportedFormats() rather than browser-name guessing. For example, QR-only uses the native engine if QR is supported. The default ten-format set can require ZXing even when the browser exposes BarcodeDetector, because some of those formats may be unavailable natively. Previously evaluated JavaScript stays cached by the browser; the field does not claim to unload it. Only one decoding operation runs at a time. The fallback uses a preview surface capped at 1,280 pixels on its longer edge. scanInterval() controls the minimum cadence between attempts; a slow attempt never starts another in parallel. Reader instances and the grayscale buffer are reused between attempts; decoding does not create a second camera stream. The ZXing fallback currently performs pixel decoding on the main thread, so recognition time depends on the device and image. Narrowing the format list and reducing decodeFps() can reduce its CPU cost.
The scanner releases the stream on closing, owner disposal or page departure. With pauseWhenHidden() enabled, it releases the camera while the document is hidden and restarts when visible. Permission denial and camera errors leave the scanner closable and offer a retry.
Camera access requires HTTPS or localhost, browser permission and an available camera. Embedded pages also need an appropriate camera Permissions Policy. Browser and hardware support determine available formats, torch and device switching. Mobile autoplay policies can prevent sound playback.
The confirmation sound is a declared, published component resource. It is prepared only after the scan-button gesture, and it does not delay accepting a code. Use the normal asset publication step when deploying or updating the package; no separate sound-publishing command is required.

Appearance

The input reuses FLEX Text Input’s presentation, focus outline, sizes and rounding. Its scan action stays on the right.
Sizes: sm, md, lg. Variants: primary, secondary, soft, flat; ghost remains supported and uses the flat input presentation.

All scanner options

These options accept a Closure for dynamic configuration unless shown otherwise. They extend the normal Filament field options such as label(), helperText(), required(), disabled() and readOnly(). scanInterval() and decodeFps() configure the same cadence; whichever you call last takes precedence. autoSubmit() does not choose a Filament modal action for you. Use its event to connect workflows whose submit control is outside the enclosing form. All normal form validation still applies.

JSON field schemas

The field type is barcode.
The scanner configuration keys are formats, confirm_scan, continuous, beep_on_scan, auto_submit, camera_facing, scan_delay, scan_interval, decode_fps, allow_camera_switch, preferred_device_id, store_detected_format, pause_when_hidden, allow_manual_input, validate_checksum, scan_button_label and modal_heading. Keep PHP callbacks such as barcodeRule() in trusted application code.
Last modified on October 16, 2026