fauzie811/filament-list-entry
fauzie811/filament-list-entry is a Filament package for Laravel that provides a reusable list entry component, making it easy to render records as clean, compact, customizable list items in admin panels and dashboards.
fauzie811/filament-list-entry is a Filament form component for editing a flat list of values inside a single form field (tags, aliases, keywords, short notes, codes). It is not a relation manager and not a full repeater — it stores the list as one dehydrated array on the record.
Minimal setup:
composer require fauzie811/filament-list-entry
composer.json for the supported Filament major (v3 vs v4) and Laravel constraint, then the package README for the exact namespace of the component class (Fauzie811\FilamentListEntry\Forms\Components\...).php artisan vendor:publish --tag="filament-list-entry-config". Most installs of a single-purpose form field do not need it.First use case — an editable tag list on a Post resource:
use Fauzie811\FilamentListEntry\Forms\Components\ListEntry;
ListEntry::make('tags')
->label('Tags');
with protected $casts = ['tags' => 'array']; on the model. That's the whole loop: add the field, cast the column, save the form.
JSON column is the default storage shape. The field's state is an array of scalars, so a json/array-cast column round-trips cleanly. If you must store a delimited string, do the transform in a mutator on the model rather than fighting the field's state.
Pair it with a table column, not a repeat. For display, render the same array read-only:
TextColumn::make('tags')->badge()->separator(',')
// or ->formatStateUsing(fn ($state) => implode(', ', (array) $state))
Use it in the places a simple scalar field goes. Because it is a Forms\Components\Field, it composes with wizards, ->hidden(), ->disabled(), Section layouts, and the action modal forms. Repeater also works there but carries per-entry schema weight you don't need for a single value.
Choose between this and Repeater deliberately. One value per row → this component. Two or more fields per row, per-row validation sets, or per-row actions → Filament's Repeater. Mixing the two (a list-entry inside a repeater) is legal but makes state debugging noticeably harder.
Validation lives on the wildcard path. Attach rules to the field and expect keys like data.tags.0 in the error bag:
ListEntry::make('tags')
->rules(['array', 'max:10'])
->rule(fn () => function ($attribute, $value, $fail) {
// $attribute is like data.tags
});
Testing. Standard Livewire form test — livewire(CreatePost::class)->fillForm(['tags' => ['php', 'laravel']])->call('create')->assertHasNoFormErrors(); then assert the persisted JSON.
'tags' => 'array', you get Array to string conversion on save or a literal ["a","b"] string in the DB. Verify with Model::find($id)->getRawOriginal('tags').[] or null depending on the component's defaults. If the column is NOT NULL, normalise in the model ($attributes['tags'] ?? []) or use ->default([]).v1.0.0...v1.0.1). There is nothing to migrate; constrain to ^1.0 and take patches. The changelog link is the only artifact — diff src/ against your installed version if you need to know precisely what moved.->afterStateUpdated(fn ($state) => dump($state)) and ->dehydrateStateUsing(...) are the fastest way to see what the field hands to the model. Filament's ->live() also lets you react to list edits (e.g. slug previews).addButtonLabel, minItems/maxItems, reorderable where exposed) and to wrapping it in your own component class if you need a different entry schema.How can I help you explore Laravel packages today?