gabrielesbaiz/nova-ajax-select
Nova Ajax Select is a Laravel Nova field that adds AJAX-powered searchable select inputs, loading options asynchronously so forms can handle large datasets without bloating the page. It supports remote search, custom endpoints, and a smooth Nova-native experience.
Architecture fit. gabrielesbaiz/nova-ajax-select is a Nova field package, not a framework or service — it slots into the existing Nova resource layer as a drop-in replacement for Select. The 2.0.0 architecture change matters more than it first appears: parent() no longer walks the Vue component tree with a bespoke watcher, it registers a Nova dependency. That means the field now participates in Nova's own dependency graph alongside dependsOn(), hide(), show(), and readonly(), and works inside panels, pivot forms, and action modals. For a TPM this is the headline: the field is now a first-class Nova citizen rather than a parallel implementation that happens to render.
Integration feasibility. Low-to-moderate effort, gated almost entirely by stack currency. The hard floor is PHP 8.3+, Laravel 12 or 13, and Nova 5 (licensed separately). Teams on Laravel 10/11 or Nova 4 cannot use this release at all — that constraint is stricter than most packages we evaluate and should be checked before anything else.
Technical risk.
alexwenzel/ajax-select registered the same asset handle. Nova resolves scripts by name with ->first(), so one bundle was silently never served and its field rendered as an unknown component. The release notes require removing the other package. This is a silent failure mode — no exception, no log line, just a broken field — which makes it the item most likely to burn support hours.get(), parent(), the NovaAjaxSelect class, and the {value, display} payload all still work but are deprecated for 3.0. A major version is already signposted. Any code we write against these surfaces has a known expiry date.Key questions.
alexwenzel/ajax-select anywhere in the codebase? If so, this is a migration, not an install.cacheScope() cover every axis our tenancy varies on, or only the obvious one?Stack fit. Clean, provided the stack gate passes. The package adds no routes, no middleware, no service provider surface we have to reason about — every resolution rides Nova's existing field-sync request, which is already authorized. That is a meaningful security-posture win versus a package that bolts on its own endpoints and its own authorization logic.
Migration path.
composer require, define the field, point it at a closure, model, relation, or backed enum. Minimal ceremony.get(), parent(), the class name, and the payload shape are all preserved. But the upgrade guide recommends three cleanups that we should do in the same change window rather than deferring: delete the now-unused routes, drop the shadow detail Text fields, and remove canSee() workarounds that only existed because dependsOn() never fired. Deferring these leaves dead code and, worse, leaves two sources of truth for labels.alexwenzel/ajax-select: remove it first, in its own commit, and verify the affected fields render before introducing the new package. Doing both in one deploy makes the silent-collision failure indistinguishable from a misconfiguration.Compatibility. The {value, display} payload is stable through 2.x, so downstream consumers (index columns, detail views, any custom rendering) don't need changes. Labels now render on index and detail natively, which lets us delete the duplicate Text field pattern — a small but real reduction in resource-definition noise across every affected resource.
Sequencing.
alexwenzel/ajax-select; remove and verify if present.canSee() workarounds).cacheScope() wherever tenancy applies before enabling caching, not after.Maintenance. Low ongoing code footprint — it's a field, not a subsystem. The real maintenance load is version-tracking: Nova 5 today, Nova 6 whenever that lands, and a 3.0 of this package already announced. Budget a recurring line item for "verify field still renders after Nova upgrade," because the failure mode is silent and won't surface in a test suite unless we write a rendering assertion for it.
Support. Documentation is above average for a package this size — dedicated docs site, a guide, and an upgrade guide with specific cleanup instructions. Support channel is GitHub issues, i.e. best-effort with no SLA. Acceptable for an admin-panel field; not acceptable if this pattern ever migrates into a customer-facing surface.
Scaling. The 2.0.0 model is a genuine improvement at scale: server-side search across named columns means option sets no longer ship in the form payload, and validation is a single membership query rather than a materialized Rule::in. The costs move to the database — one resolution query per field-sync, one membership query per validation. On relation-backed options, watch for N+1 patterns in index listings where many rows each resolve labels. Optional caching with cacheScope() is the intended mitigation; treat it as required, not optional, for any large or multi-tenant option set.
Failure modes.
cacheScope() is omitted or under-specified on a multi-tenant resource, users see another tenant's options. This is the one failure mode with a data-exposure shape rather than a UX shape; it deserves explicit review sign-off.get()/parent()/NovaAjaxSelect — a known, dated break if we adopt the deprecated surfaces now.Ramp-up. Fast for anyone who has built a Nova field — the API is a Select with a resolver, and the docs cover the four resolver types. The non-obvious knowledge is all operational, not syntactic: the collision rule, the cache-scope rule, and the deprecated-surface list. Those three belong in a short internal note attached to the package, because none of them are discoverable from reading a resource definition.
How can I help you explore Laravel packages today?