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

Filament Money Field Laravel Package

pelmered/filament-money-field

A Filament form field for handling monetary values with the Money PHP library. Store and edit amounts as integer minor units, format them for display, and support multiple currencies with locale-aware input and validation.

View on GitHub
Deep Wiki
Context7

Getting Started

Install (this is a pre-release — pin it explicitly):

composer require pelmered/filament-money-field:"2.0.0-beta.4"
# or, to track the 2.0 line:
composer require pelmered/filament-money-field:"^2.0@beta"

A bare composer require pelmered/filament-money-field will not pick up a beta, and ^2.0 alone may resolve to the newest beta or the eventual stable — decide which you want before you commit the lock file.

Where to look first:

  1. The README on GitHub — the examples are the de-facto API reference, and PR #107 in this release was literally a fix to a README example, so make sure you are reading the README as of 2.0.0-beta.4 and not a cached copy from v1.
  2. src/Forms/Components/MoneyField.php — the public fluent methods (currency(), locale(), divideBy(), stripCharacters(), etc.) are all there; that file is the real documentation.
  3. tests/ — the Livewire/Filament form tests show the exact input string → stored value contract, which is the thing most likely to bite you.
  4. The v1 → v2 upgrade notes / PR #81 ("2.0") — that is the breaking-change commit; read its diff before migrating an existing app.

First use case — a price field on a resource where the database stores integer minor units (cents/öre):

use Pelmered\FilamentMoneyField\Forms\Components\MoneyField;

MoneyField::make('price')
    ->currency('SEK')
    ->locale('sv_SE')
    ->divideBy(100);

The field renders a locale-formatted, currency-suffixed input but dehydrates to an integer. That single asymmetry (display in major units, store in minor units) is the core mental model for the whole package.

Implementation Patterns

Store minor units, format on the way in and out. Keep your migration as unsignedBigInteger('price') and let divideBy(100) handle the boundary. If you would rather store a Money object or a decimal string, do that conversion in a model cast/accessor and don't also use divideBy() — pick one seam and stay there.

Locale and currency are independent. ->locale() controls separators and symbol placement (1 234,56 kr vs $1,234.56), ->currency() controls the symbol and minor-unit exponent. They are not derived from app()->getLocale() or from each other by default, so set both explicitly on every field rather than relying on ambient config.

Reactive currency switching. The bug fixed in this release (#108) is the classic pattern of a Select::make('currency')->live() driving MoneyField::make('price')->currency($get('currency')). It now behaves in Filament v4, but the pattern still requires care:

Select::make('currency')
    ->options(['USD' => 'USD', 'SEK' => 'SEK', 'JPY' => 'JPY'])
    ->live()
    ->afterStateUpdated(fn (Set $set) => $set('price', null)), // reset stale state

MoneyField::make('price')
    ->currency(fn (Get $get) => $get('currency') ?? 'USD')
    ->locale(fn (Get $get) => $get('currency') === 'SEK' ? 'sv_SE' : 'en_US');

Note the JPY trap: currencies with a 0 minor-unit exponent will not divide by 100 the way you expect. Test it.

Pasted / dirty input. ->stripCharacters([' ', "\u{00A0}", 'kr', '$']) handles non-breaking spaces and stray symbols that users copy out of spreadsheets. Pair it with the locale so the decimal separator is unambiguous.

Form + table symmetry. The field only covers forms. For tables and infolists, format the stored integer with Laravel's Number::currency($value / 100, 'SEK', 'sv_SE') (or a Brick/Money formatter) in a TextColumn::make('price')->formatStateUsing(...). Keeping one helper for "format minor units for humans" used by both the field config and the column avoids drift.

Validation lives in major units, storage in minor. ->min(0)->max(99999) is evaluated against what the user sees, while your Rule::max() / DB column sees the divided value. Decide which layer owns the constraint and write a test asserting the persisted integer, not the rendered string.

Testing. Filament form tests are the fastest way to pin behaviour across a v3→v4→v5 move:

livewire(CreateProduct::class)
    ->fillForm(['price' => '1 234,56'])
    ->call('create')
    ->assertHasNoFormErrors();

$this->assertDatabaseHas('products', ['price' => 123456]);

Write that test before upgrading Filament. It will catch the currency-hydration regression class of bug immediately.

Integration tip for multi-panel apps: if you have panels on different Filament majors during a staged upgrade, this package cannot span both — the composer constraints resolve per-project, so upgrade panel-by-panel in separate deployments, not in one monorepo.

Gotchas and Tips

This is 2.0.0-beta.4, not 2.0.0. Four betas deep with a "2.0" mega-PR (#81) at the root means the public API is still moving. Pin the exact version, don't use ^2.0 in production, and budget for a re-read of the README on each beta bump.

"Allow Filament V5 installation" (#109) is a Composer constraint loosening, not a support guarantee. The PR title is literally about installability. Filament v5 was not the target of the v4 work in #100, and there is no v5 test matrix mentioned here. If your app is on v5, treat the field as unverified: smoke-test rendering, dehydrate, and reactive currency before shipping. If you're on v4, that's the tested path.

The v4 change is a major for a reason. Filament v4 reworked form component internals and testing helpers; a v1/v2-beta field built against v3 will not merely warn. Read PR #81 and #100 diffs, and expect to update any custom subclass of MoneyField or any macro()/configureUsing() call that touches internals.

Currency-change state hydration (#108). If you were previously working around the v4 currency bug, remove the workaround — double-resetting state now can blank the field on edit forms. The symptom to watch for is an edit form that shows an empty price until you touch the currency select.

divideBy/stripCharacters mismatch is the #1 silent data bug. A field that divides by 100 but doesn't strip the locale's thousands separator (often a non-breaking space, \u{00A0}, not a regular space) will happily store 1 for 1 234. Never trust the browser-side parse; assert the integer in a test.

Cache clearing after upgrades. Filament caches components and Blade views; after swapping majors run php artisan filament:clear-cached-components (or optimize:clear) before concluding the field is broken. Package config, if published, is also cached — php artisan config:clear when changing default locale/currency.

Locale vs. user expectation. ->locale() should track the user's formatting preference, ->currency() the record's currency. Hard-coding both to the app default produces the classic "Swedish user sees $1,234.56" complaint that no amount of backend correctness fixes.

Extension points to prefer. MoneyField::configureUsing(fn (MoneyField $field) => $field->locale('en_US')) in a service provider is the cleanest way to set house defaults without repeating yourself across every resource. For anything beyond formatting, reach for formatStateUsing/dehydrateStateUsing on the instance rather than subclassing.

Debugging dehydrate. When stored values look wrong, ->dehydrateStateUsing(function ($state) { dump($state); return $state; }) will tell you in one request whether the problem is parsing (wrong value in) or division (wrong value out). Do this before opening a GitHub issue — the input string and the resulting integer are what maintainers will ask for anyway.

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.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums