ringlesoft/laravel-selectable
Laravel Selectable generates HTML select options directly from Laravel collections using a fluent, chainable API. Customize labels and values with strings or closures, set selected/disabled options, add data attributes, grouping, and export arrays for AJAX or SPAs.
<option> markup or a structured array. The real decision isn't "do we need this capability" (every Laravel CRUD surface does) — it's whether a ~single-maintainer, 5-star, zero-dependent utility is cheaper to adopt than the 40–80 lines of internal Blade component most teams already write. Treat it as a utility-tier buy, not a platform-tier one.withLabel, withValue, withSelected, withDisabled, withDataAttribute, withClass, withId, groupBy) maps directly onto recurring backlog tickets: "show full name instead of email in the dropdown," "pre-select the current assignee," "grey out inactive accounts," "group users by department." Those are usually 1-point stories; this collapses them to one-line diffs.toSelectItems() returns a stable, documented shape (label, value, selected, disabled, dataAttributes, classes). That makes it a viable serialization contract between Laravel and a Vue/Alpine/Livewire front end — the one part of this package with more than cosmetic value, because it standardizes a payload format your front end can rely on.Adopt (or pilot) when:
<option value="{{ $x->id }}" {{ $selected ? 'selected' : '' }}> block more than a handful of times.@foreach + @if soup.optgroup support for free via groupBy() — the highest-effort thing to hand-roll correctly.Look elsewhere when:
<option> tags — a performance and UX dead end. Use a proper async select backed by an API.{!! ... !!}). Before shipping anywhere user-controlled strings (names, titles) reach a label, confirm the package escapes label/value content. If it doesn't, that's an XSS exposure introduced by convenience — a hard blocker, not a nitpick.require constraints against your matrix before anyone writes code; the PHP badge is the fastest gate.To executives (30 seconds): A small, free MIT utility that removes repetitive boilerplate from our Laravel admin forms and standardizes how dropdowns get rendered. Expected benefit is modest but real: fewer small form bugs, faster delivery of routine CRUD tickets, and a consistent payload for our front-end selects. Cost is one dependency with no infrastructure impact. Risk is low if we isolate it behind our own helper and pin the version — it's maintained by a single author with minimal adoption, so we treat it as something we could absorb in an afternoon rather than a platform commitment. Recommendation: pilot in internal admin screens, not in customer-facing or payment flows.
To engineering (the actual pitch): One composer require, no config, no service provider. $collection->toSelectOptions() for the simple case; chain toSelectable()->withLabel(fn($u) => "{$u->first_name} {$u->last_name}")->withSelected($ids)->withDisabled(...)->withDataAttribute(...)->toSelectOptions() for the messy case; ->toSelectItems() when you need a JSON array for Vue/Alpine instead of HTML. groupBy() gives you optgroup without hand-rolling it, and it handles both Eloquent models and plain arrays. Two asks before merge: (1) wrap it in a single internal Blade component/helper so swapping it out is a one-file change, and (2) write one test asserting labels and values are HTML-escaped — if they aren't, we escape at the wrapper or we walk away. Pin the version, no floating constraint, and keep it out of any code path where an unescaped label would be an XSS vector.
Bottom line for the decision log: Low-cost, low-risk convenience dependency with a genuinely useful toSelectItems() serialization contract and optgroup support. Adopt narrowly, wrap defensively, escape-verify first, and don't mistake it for a select/search strategy.
How can I help you explore Laravel packages today?