Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Select Or Custom Laravel Package

lynndigital/select-or-custom

Laravel package that adds a select-or-custom form field: users can pick from a predefined list of options or type their own value instead, with validation covering both the chosen option and any custom text they enter.

View on GitHub
Deep Wiki
Context7

Getting Started

lynndigital/select-or-custom (published from the 0x15f/select-or-text repo) is a Laravel Nova form field that behaves like a Select but lets the user type a value that isn't in the options list. It's aimed at the common "pick from these categories, or add a new one on the fly" case — source/channel fields, tags, department names, referral sources — without forcing a second free-text field into the form.

Minimal steps:

  1. composer require lynndigital/select-or-custom
  2. Nova auto-discovers the service provider in most setups; if yours doesn't, add the provider listed in the package's composer.json extra.laravel.providers block to config/app.php.
  3. If the package ships prebuilt assets, nothing else is needed. If not, run npm install && npm run prod inside the package (or copy its resources/js component into your own field) and php artisan nova:publish.
  4. Use it like a Select:
use Lynndigital\SelectOrCustom\SelectOrCustom; // confirm exact class in src/ or README

SelectOrCustom::make('Source')
    ->options([
        'organic'  => 'Organic',
        'referral' => 'Referral',
        'paid'     => 'Paid',
    ])
    ->rules('required', 'max:255'),

Where to look first: the README for the field's actual API, then src/ for the field class (especially how it hydrates/fills and what it writes back), then resources/js/components/Field.vue for how the custom value is captured and submitted. The Vue component is where most surprises live (trimming, empty-string handling, whether typing a value that matches an option key is treated as the option or the custom string).

First realistic use case: a single varchar column that today is populated by a Select, where ops occasionally needs an option you didn't anticipate. You get the constrained UX most of the time and an escape hatch without a schema change.

Implementation Patterns

  • Single string column, no pivot. The field resolves to one scalar value. Keep the underlying column a string (or nullable string) and store the chosen key or the typed text in the same place. Don't try to model this as a belongs-to-many.
  • Options from config/enum, not hard-coded. Build the options array in a dedicated method or config file so index filters, exports, and validation can reuse it:
->options(config('crm.sources'))
  • Bootstrap options from existing data. For fields where the "custom" values accumulate (tags, channels), merge curated options with Model::distinct()->pluck('source') so previous custom entries become selectable next time. Sort and dedupe; watch for case-only duplicates.
  • Validation. Use ->rules('required', 'max:255') and, if you want a controlled vocabulary, a Rule::in(array_keys($options)) — but only when you actually want to forbid custom values. Most of the time you don't, so skip in: and rely on max/string.
  • Display on index/detail. Decide whether to show the raw stored value or a label. If you have a label map, add ->displayUsing(fn ($value) => $options[$value] ?? $value) so custom values render as themselves and known options render as friendly labels.
  • Reactive forms. The field participates in Nova's DependsOn like other fields; wire ->dependsOn(['country'], ...) if the option list is derived from another field, but confirm the component forwards the dependency (it may not, given the package's size — test before relying on it).
  • Normalize on save. If you subclass or add ->fillUsing(...), trim whitespace and optionally Str::slug/lowercase custom entries so "Paid " and "paid" don't both end up in the column. Do this centrally; the field itself likely doesn't.
  • Reuse for filters/metrics. Once values are in the column, build Nova filters and cards off the same options map so the vocabulary stays consistent across the admin.

Gotchas and Tips

  • Maintenance risk is the headline gotcha. 10 stars, zero dependents, low opportunity score: treat this as a vendored dependency. Pin the version in composer.json, and be prepared to fork it into your own packages/ (or a private VCS repo) the first time a Nova upgrade breaks it. Budget an afternoon for that; it's a small field, so the fork is cheap.
  • Name mismatch. The package is lynndigital/select-or-custom but the repo is 0x15f/select-or-text. The namespace/class name may not match the package name — verify in src/ before copy-pasting use statements from the README, and check composer.json for the actual autoload.psr-4 mapping.
  • Custom value collides with an option key. If a user types "paid" and paid is already an option key, you'll get the same stored string either way — usually fine, but it makes "was this a curated option or a custom entry?" unanswerable later. If that distinction matters, store a parallel flag column.
  • in: validation silently breaks the feature. The most common self-inflicted bug: adding Rule::in($options) "for safety" and then wondering why custom entries fail validation. Audit any request-level FormRequest rules on the same column too.
  • Empty string vs null. Typing then clearing the input can submit '' rather than null. Add ->nullable() and normalize in a mutator if downstream code checks is_null.
  • Index display and search. Custom values won't have a label, so index rows can look inconsistent. Make the field ->searchable() on a text column, and test WHERE filters against both curated and custom values. Sorting by this column will be alphabetical on the raw string, not on display order.
  • Asset build. If dist/js/field.js is missing or stale, the field renders as a plain text input or nothing at all. Check public/vendor / vendor/.../dist and rebuild. Browser console errors after a Nova upgrade usually mean the Vue component targets an older Nova mix setup.
  • Type juggling. If options are integer-keyed (e.g. IDs) but the column is varchar, the field may submit "3" (string) while your model expects 3. Cast consistently with $casts and check the resolved value before it hits the database.
  • Extension point. The cleanest long-term move is to subclass the field and override the display/fillUsing logic rather than patching vendor/. Keep your subclass in app/Nova/Fields/ so a composer update can't clobber it.
  • Debugging checklist: (1) confirm the field appears in nova:check/the form at all, (2) inspect the network payload on save to see whether the custom value is sent, (3) dd() in the field's resolve/fill methods to confirm what's written, (4) check the Vue component's modelValue watcher if the value doesn't repopulate on edit.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package