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

Enum Field Laravel Package

suleymanozev/enum-field

Enum Field for Filament provides a simple Laravel form component that turns PHP enums into selectable options, with support for labels, colors, and validation so enum-backed values are easy to manage in Filament admin panels.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the field alongside Nova (it assumes laravel/nova is already required in your project):

composer require suleymanozev/enum-field

Most custom Nova fields ship a compiled JS bundle, but if resources/js is present in the vendor directory you'll need to publish and rebuild assets:

php artisan vendor:publish --tag=nova-assets   # if the package registers a tag
php artisan nova:publish

Where to look first, in order:

  1. README.md — check the exact make() signature and whether it expects an enum class, an array, or a closure.
  2. src/EnumField.php (or similarly named class) — confirm the component string and the public setters it exposes (->options(), ->enum(), ->labels(), etc.).
  3. resources/js/ — verify whether the field is a thin wrapper over Nova's built-in Select or a custom component; this determines which Nova props (displayUsingLabels, searchable, rules) will actually work.

First use case — a model with a backed enum cast:

// app/Enums/Status.php
enum Status: string
{
    case Draft   = 'draft';
    case Published = 'published';
}
// app/Models/Post.php
protected $casts = ['status' => Status::class];
// app/Nova/Post.php
use Suleymanozev\EnumField\EnumField;

public function fields(Request $request)
{
    return [
        EnumField::make('Status')
            ->options(Status::class),
    ];
}

If that renders a select on the form and a readable label on index/detail, you've validated the package end-to-end. If the constructor signature differs, the src/ file is the source of truth — with a package this small, reading the 50–100 lines is faster than searching for docs.

Given the package has no dependents and effectively no community footprint, treat "getting started" as a 15-minute source audit: confirm the Nova version it targets (composer.json → laravel/nova constraint), confirm the Vue component is compiled, and confirm it degrades gracefully on Nova 4 vs Nova 5 before wiring it into more than one resource.

Implementation Patterns

Centralize option lists on the enum itself. Rather than duplicating label arrays in every resource, give the enum a label() method or static options() and let the field consume it. This keeps filters, actions, and validators in sync:

enum Status: string
{
    case Draft = 'draft';
    case Published = 'published';

    public function label(): string
    {
        return match ($this) {
            self::Draft => 'Draft',
            self::Published => 'Published',
        };
    }

    public static function options(): array
    {
        return collect(self::cases())
            ->mapWithKeys(fn ($c) => [$c->value => $c->label()])
            ->all();
    }
}

Then EnumField::make('Status')->options(Status::options()) (or ->options(Status::class) if the field accepts the class and calls cases() itself).

Consistent index vs. form behavior. The common split is: on forms you want a select of raw values; on index/detail you want the human label. If the field doesn't do this automatically, use Nova's displayUsing / resolveUsing hooks:

EnumField::make('Status')
    ->options(Status::class)
    ->displayUsing(fn ($value) => $value instanceof Status ? $value->label() : $value)
    ->onlyOnForms(),

Text::make('Status', 'status')
    ->displayUsing(fn ($value) => $value?->label())
    ->exceptOnForms(),

Or, if the field handles both, skip the duplication and verify in the browser.

Pair the field with Nova filters. Enums are a natural fit for a dropdown filter. Define the filter options from the same Status::options() source so a new case never has to be added twice:

public function options(Request $request)
{
    return Status::options();
}

Use it inside actions and modals. Because Nova fields are reused across resources/actions, the field is handy for a "Change status" action's fields() array — same enum, same rendering, no extra Vue work.

Validation: always add explicit rules; don't rely on the field to constrain input server-side:

EnumField::make('Status')
    ->options(Status::class)
    ->rules(['required', Rule::enum(Status::class)])

Reuse for other enums. If the package accepts a class string, one EnumField covers every backed enum in the app — user roles, order states, visibility flags. Build a tiny app/Nova/Fields/StatusField.php wrapper if you find yourself passing the same options()/displayUsing() chain everywhere.

Gotchas and Tips

  • Vet before you depend. Zero stars, zero dependents, no issue history means you are the QA. Read src/ and confirm the composer.json Nova constraint matches your installed Nova major. Pin the version in composer.json and consider vendoring/forking the single field class into app/Nova/Fields/ if it's under ~100 lines — you'll own a file instead of an abandoned dependency.
  • Asset rebuild is the #1 "field is blank" cause. If the form renders nothing, the compiled JS is stale or wasn't published. Check public/vendor/nova / run php artisan nova:publish, then hard-refresh. Custom fields do not hot-reload.
  • Enum cast is mandatory. Without protected $casts = ['status' => Status::class], Nova receives a raw string and any ->displayUsing(fn (Status $s) => ...) type hint will throw. Guard with ?-> and a union check when values may be legacy/null.
  • Nullable enums. With ?Status and a null DB value, ensure the select has an empty option and that ->nullable() (Nova) plus 'nullable' in the rules are both set — otherwise saving an untouched form writes '' and fails the DB enum/column constraint.
  • Label mapping vs. storage. Never store labels; store ->value. If the field's options() maps label => value in the opposite direction from what you expect, the select will save labels and silently corrupt data. Verify by saving and inspecting the row.
  • Index sorting/filtering hits the DB, not the field. The Vue field only affects rendering; sortable() on an enum column sorts alphabetically by raw value, which often looks wrong. Either accept raw-value ordering or add a computed/orderByRaw sort.
  • Nova 4 vs 5 differences. Mixins, FormField vs Field base classes, and resolveUsing semantics changed. If the package targets one major, test the other explicitly rather than assuming.
  • Debugging tip: ->help() and Log::info($field->jsonSerialize()) in the resource's fields() will show you exactly which meta (options, component name) the field sends to Vue. If meta is empty server-side, the bug is in the PHP class; if meta is populated but the UI is blank, it's the JS asset.
  • Fallback plan. If the field turns out to be a thin wrapper, Nova's built-in Select::make('Status')->options(Status::options()) already covers 90% of use cases with no third-party risk. Reserve the package for the cases where it genuinely adds a label/display layer you don't want to reimplement.
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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle