jeffersongoncalves/filament-cnpj-field
A Filament form field for Brazilian CNPJ input, adding masking and validation to Laravel admin panels. Simplifies collecting and verifying company registration numbers in Filament forms.
This is a Filament v5-only package — there is no v4 path, so the first step is confirming your panel is already on v5 before you composer require. If you're mid-upgrade, park this until the panel boots cleanly.
composer require jeffersongoncalves/filament-cnpj — it pulls jeffersongoncalves/laravel-cnpj, which is where the actual check-digit algorithm and Minha Receita HTTP client live. Skim that dependency's README too; the field is a thin form-component wrapper around it.php artisan vendor:publish --tag=...). If a config file exists, it will hold the lookup endpoint/timeout — set those before writing any forms, because the defaults will point at a public API you may not want to hammer from production.vendor/jeffersongoncalves/filament-cnpj/src/ — specifically the CnpjInput class. Read the public methods before reading the docs; for a package this small the class is the documentation, and you'll want to know exactly which fluent methods exist for mask mode and lookup rather than guessing from the release note.First use case: a CnpjInput::make('cnpj') field dropped into an existing CompanyResource form schema. That alone gets you the mask and server-side check-digit validation — no lookup, no autofill, no network. Ship that first, confirm it saves digits cleanly, and only then turn on the Minha Receita integration.
Start masked-only, add lookup second. The validation and mask are self-contained and safe. The company lookup is an outbound HTTP call with someone else's uptime — treat it as an enhancement, not part of the core field contract. Wire it behind a separate fluent call so you can disable it per-field.
Normalise on the way in, format on the way out. Keep the database column holding the unmasked 14-character string and let the field handle display. In practice that means the field's dehydrated state should be digits-only (or alphanumerics-only for the new format) and any ->formatStateUsing() you add should re-apply the mask for edit forms. Do the stripping in one place — a mutateFormDataBeforeSave() or an Eloquent mutator — not scattered through the form.
Use it for table filters too. Filament lets you reuse the same component inside ->filters([...]) and inside action modal forms. A masked CNPJ filter is a big usability win on a company list and costs nothing extra once the field works in the resource form.
Extract shared schemas. If CNPJ appears on more than one resource or panel, put the field in a small static CompanyForm::schema() / CnpjFields::make() helper. You'll want one place to flip mask mode when you support both CNPJ formats.
Handle the lookup as a UX affordance. Trigger it on blur (->live(onBlur: true) plus afterStateUpdated) and fill sibling fields (razao_social, nome_fantasia, address) only when they're empty — never silently overwrite what the user typed. Guard the handler so a failed lookup leaves the form fully usable.
Test with Http::fake(). Anything touching Minha Receita must be faked in your suite or your CI becomes dependent on a third-party Brazilian API. Assert on the unmasked state value; that's the contract that actually reaches your database.
string, not an integer/bigint — if you have legacy rows in a numeric column, plan a migration before enabling the alphanumeric mask. The check-digit algorithm also differs between the two formats, so don't hand-roll a regex validator alongside this package; use its rule so both formats stay correct.formatStateUsing / dehydrate pair first.laravel-cnpj dependency before trusting it with anything you send to a public endpoint — you're effectively auditing two packages.->rules() / ->mask() explicitly over forking the vendor view. If you need a bespoke mask or a different lookup provider, override the field's view or swap out the lookup call rather than patching vendor code — you'll be upgrading this alongside Filament itself.How can I help you explore Laravel packages today?