Download the PHP package xylo/multiselect-two without Composer
On this page you can find all versions of the php package xylo/multiselect-two. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download xylo/multiselect-two
More information about xylo/multiselect-two
Files in xylo/multiselect-two
Package multiselect-two
Short Description A Filament two-sided multiselect field with search, barcode scan, descriptions, and a natural accent theme. Compatible with Filament 4 and 5.
License MIT
Homepage https://github.com/xylo/multiselect-two
Informations about the package multiselect-two
Xylo Multiselect Two
A Filament form field for transferring items between two lists — available and selected — with search, barcode scanning, descriptions, count badges, and a natural green accent.
Compatible with Filament 4.x and 5.x.
Installation
If you install from a local path:
Publish assets (recommended after install / update):
Optional translations:
Usage
Without title / subtitle:
Rich options (label + description + barcode + sku in one array)
Barcode scanning
The barcode input takes whatever a keyboard-wedge scanner types, then Enter. Matching happens entirely in the browser against the options already on the page — a scanned code is never sent to the server.
A scan is resolved in three tiers, stopping at the first one that hits:
- Exact — the code as typed, against
barcodes(),skus()and option values. - Normalized — case and every separator (spaces, dashes, dots) removed from both sides.
- GTIN-14 — numeric codes left-padded to 14 digits.
Tier 3 is what makes catalogs work in practice: a label printed as UPC-A 012546011112
scans into a product stored as EAN-13 0012546011112. Tiers 2 and 3 apply to barcodes()
and skus() only — an option value (usually a record id) is matched exactly or not at all,
so an id can never shadow a real barcode.
A scan never guesses. If a code matches more than one option, nothing is selected and the component reports the ambiguity so a human decides. Every outcome is shown inline under the input:
| Outcome | When |
|---|---|
added |
Exactly one match, allowed, not selected yet |
already_added |
The matched option is already in the selected panel |
not_allowed |
The matched option is excluded by limitTo() |
not_found |
No option matches |
ambiguous |
More than one option matches |
Instant or Enter-to-scan
By default the code is resolved when the operator presses Enter, which is what a
keyboard-wedge scanner sends after the digits. instantScan() resolves while typing
instead:
Instant mode is deliberately quiet: while typing, only an unambiguous match is added and misses report nothing, because a half-typed code is not a failed scan. Enter still works and still reports every outcome.
The delay matters. Without it, a prefix of a long code could match some other product's shorter barcode mid-burst and add the wrong row — waiting for the input to settle is what prevents that. Lower it only if your scanner is slow; raise it if operators type by hand.
Other options
Opt into searchOnScanMiss() if you would rather have an unresolved code dropped into the
available search box than left to the result line alone.
Messages live under the scan.* translation keys:
Search benefits from the same normalization: typing 0125-4601 1440 finds a product
stored as 012546011440.
Features
- Two-sided transfer UI (available ↔ selected)
- Count badges on both panels
- Barcode scan input (Enter to add) with GTIN-aware matching and an inline result line — see Barcode scanning
- Search / filter on both sides (name, SKU, barcode, formatted codes) with 200ms debounce
- Scroll windowing — renders
pageSizerows at a time (default 80), loads more on scroll - Prebuilt option list +
Setmembership for fast filtering on large catalogs - Dynamic options remount via
wire:key(safe for dependent fields like Free Reward ⊆ Products to Buy) - Item title + subtitle (e.g. price)
- Chevron move actions + remove (X) on selected rows
- Add all shown / Remove all (Add all adds every filtered available item, not only the first rendered page)
- Soft accent color only on hover (items + bulk buttons)
- Theme-aware colors: text/borders/surfaces follow Filament gray tokens + light/dark automatically
- Accent:
natural, Filament colors (primary,success, …), or any custom CSS color - Optional Filament
label()/helperText()— nothing forced by the package - Works with Filament
live(),disabled(), validation, defaults - English + Arabic translations
- Multiple independent instances on the same form (e.g. Products to Buy + Free Reward)
Configuration API
| Method | Description |
|---|---|
options() |
Available choices |
descriptions() |
Subtitle under each label |
barcodes() |
Values matched by the scanner |
skus() |
Included in search + scan |
selectableLabel() / selectedLabel() |
Panel titles |
enableSearch() / searchable() |
Toggle search inputs |
enableBarcode() / barcodeScanner() |
Toggle barcode input |
barcodeStrict() |
Require byte-for-byte scan matches (disables the relaxed tiers) |
instantScan() |
Add a match while typing instead of on Enter (default off) |
instantScanDelay(120) / instantScanMinLength(6) |
Idle time and shortest code an instant scan acts on |
scanFeedback() / scanFeedbackDuration(4000) |
Inline scan result line; 0 keeps it until the next scan |
searchOnScanMiss() |
Put an unresolved scan into the available search box (default off) |
showCounts() |
Toggle count badges |
showBulkActions() |
Toggle footer buttons |
listHeight(320) |
Scroll area height in px |
pageSize(80) |
Rows rendered per chunk (scroll loads more); keep low for huge catalogs |
limitTo('other_field') |
Client-side: only show options selected on another field (no Livewire wait) |
accentColor(...) |
natural, primary/success/danger/warning/info/gray, or CSS color |
hoverColor(...) |
Shared hover for items + both buttons |
itemsHoverColor(...) |
Shared hover for both panels' rows |
availableHoverColor(...) / selectedHoverColor(...) |
Hover per panel |
buttonsHoverColor(...) |
Shared hover for Add all + Remove all |
addAllHoverColor(...) / removeAllHoverColor(...) |
Hover per button |
buttonsBackgroundColor(...) |
Shared default background for both buttons |
addAllBackgroundColor(...) / removeAllBackgroundColor(...) |
Background per button (defaults kept if unset) |
addAllLabel() / removeAllLabel() |
Footer button labels |
availableSearchPlaceholder() / selectedSearchPlaceholder() / barcodePlaceholder() |
Input placeholders |
label() / helperText() / hiddenLabel() |
Optional title & subtitle (Filament) |
Color priority (most specific wins):
- Per-part (
availableHoverColor,addAllHoverColor, …) - Group (
itemsHoverColor,buttonsHoverColor) - Shared (
hoverColor) - Default from
accentColor
Dependent fields (Products to Buy + Free Reward)
Use two separate fields. Keep Free Reward options as a subset of Products to Buy, and prune invalid rewards when qualifying changes:
The package remounts Alpine when option keys change (wire:key), so the Free Reward list refreshes when Products to Buy changes.
Example with labels from the screenshots
Accent examples:
Structural colors (titles, prices, borders, cards, inputs) always use Filament --gray-* tokens and switch with light/dark mode — no extra config.
Version compatibility
| Package | Filament | PHP |
|---|---|---|
| 1.x | 4.x / 5.x | 8.2 / 8.3 / 8.4 |
Filament 5 keeps the Forms API from 4 and mainly upgrades Livewire; this package targets both.
Credits
- Developer: Qusai Homadi
- Package: Xylo (
xylo/multiselect-two)
License
MIT
All versions of multiselect-two with dependencies
filament/filament Version ^4.0 || ^5.0
filament/forms Version ^4.0 || ^5.0
spatie/laravel-package-tools Version ^1.16