codebar-ag/filament-json-field
Codebar's Filament JSON Field adds a dedicated JSON editor to Filament forms, with syntax highlighting, validation, formatting, and a clean editing experience. Ideal for settings, metadata, and API payloads, it makes structured JSON easy to manage in Laravel admin panels.
Install the package into an existing Filament 3/4 application:
composer install codebar-ag/filament-json-field
There is no service provider to register manually on modern Laravel package discovery, but confirm CodebarAg\FilamentJsonField\JsonFieldServiceProvider is listed in bootstrap/providers.php (Laravel 11+) if auto-discovery is disabled. Ensure your model casts the target column to array or json so Filament receives a PHP array rather than a raw string:
protected function casts(): array
{
return ['metadata' => 'array'];
}
Where to look first:
formatOnBlur, height, editor options, etc.) — it is short and changes between releases.src/Forms/Components/JsonField.php — everything is in this one class; skim the setters to see what is actually configurable in your pinned version.tests/ — the fastest source of truth for how state is hydrated and dehydrated.First use case — editing a JSON blob on a resource:
use CodebarAg\FilamentJsonField\Forms\Components\JsonField;
JsonField::make('metadata')
->label('Metadata')
->formatOnBlur()
->required();
That's the whole setup. The field renders an editor, loads the decoded array, and dehydrates a JSON-encoded value on save.
Standard resource form. The idiomatic usage is a single JSON column on a model, cast to array, edited through a normal Filament form. Keep validation in the field's rules() so the user gets an inline error instead of a 500 on save:
JsonField::make('settings')
->rules(['json'])
->formatOnBlur()
->columnSpanFull();
Formatting workflow. Most teams pair the field with an explicit format action so the stored JSON is always canonical. If the package exposes formatOnBlur() / autoFormat(), prefer the blur variant — formatting on every keystroke is noisy for large payloads and fights the cursor position.
Conditional/partial editing. For "advanced settings" style UIs, wrap the field in a Section that is collapsed by default and gate it with ->visible(fn ($record) => $record?->is_admin) or ->hidden(fn (Get $get) => ! $get('show_advanced')). JSON editing is a power-user affordance; don't put it in the primary path for non-technical users.
Read-only / display contexts. On the ViewRecord page, ->disabled() (Filament's read-only state) is usually cleaner than a TextEntry, because you keep the same highlighting and formatting the editing page has. Avoid rendering JsonField in table columns — use TextColumn::make('metadata')->formatStateUsing(...) or a badge/limit instead.
Mutation before save. When the underlying column expects a string but your model doesn't cast it, normalize in the page rather than in the field:
protected function mutateFormDataBeforeSave(array $data): array
{
$data['settings'] = json_encode($data['settings'], JSON_PRETTY_PRINT);
return $data;
}
This is also the correct place to enforce key ordering (ksort) if downstream systems diff the JSON.
Integration with actions and repeaters. JsonField is a normal Filament component, so it works inside Repeater, Action::make()->form(), and relation-manager schemas. In repeaters, give each instance a clear ->label() — the browser's DOM id is generated from the name and nested array paths (form.repeaters.settings.0.json) look identical to users.
Testing. Use Filament's form assertions. Because the field state is an array, assert with the decoded shape:
livewire(EditSettings::class, ['record' => $record])
->fillForm(['metadata' => ['foo' => 'bar']])
->call('save')
->assertHasNoFormErrors();
$this->assertSame(['foo' => 'bar'], $record->fresh()->metadata);
If your cast is array, avoid asserting on the raw attribute — Eloquent will re-decode it and spacing/order differences will make the test brittle.
null vs [] vs {}. JSON round-trips are lossy in PHP: {} decodes to an empty array, which re-encodes as []. If consumers distinguish an object from an array (common with third-party APIs), either don't cast to array and hand the field a raw string, or normalize explicitly before saving.rules(['json']) check tells the user the blob is malformed but not which key broke a business rule. For anything with a known schema, add a custom closure rule or validate on after() in the form and map errors back with ->addError('data.metadata', ...).ksort (recursively) in mutateFormDataBeforeSave is the cheapest fix.post_max_size and Filament's Livewire payload limits before blaming the component.base path, subdirectory deploys), the editor may silently fall back to a plain <textarea>. Check the browser console first — the field still works, so it's easy to misdiagnose as "styling."string column cast to array is fine; a json column without a cast passes a string into the field and you'll see escaped quotes.disabled() still submits the value in some versions and not others; if you're locking a field but relying on the existing value, confirm the save path preserves it rather than overwriting with null.composer.json, and run the upgrade with a smoke test on the edit page — a Filament major bump is far more likely to break this than a patch release of the package itself.How can I help you explore Laravel packages today?