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 Laravel Package

defstudio/filament-money

defstudio/filament-money adds money-aware form fields and table columns to Filament, with formatting, casting, and storage helpers for consistent currency handling in Laravel admin panels.

View on GitHub
Deep Wiki
Context7

Getting Started

defstudio/filament-money is a thin, focused Filament bridge for brick/money. It gives you a MoneyInput form component and a MoneyColumn table component so you stop hand-rolling number formatting and currency parsing in every resource.

composer require defstudio/filament-money

There is no required publishing step — the package ships sensible defaults. Publish the config only if you want to change the package-wide fallback currency/locale:

php artisan vendor:publish --tag="filament-money-config"

Where to look first

  1. README.md — the usage surface is small enough that the README is genuinely the reference.
  2. config/filament-money.php — global default currency and locale. Set these once to your app's base currency and you can omit the arguments in 90% of your fields.
  3. src/MoneyInput.php and src/MoneyColumn.php — the two classes you will actually be using. Both are short; read them before assuming behaviour around parsing and null values.

First use case — a product price on a resource form plus its table listing:

use DefStudio\FilamentMoney\Forms\Components\MoneyInput;
use DefStudio\FilamentMoney\Tables\Columns\MoneyColumn;

MoneyInput::make('price')
    ->currency('EUR')
    ->locale('it_IT')
    ->required(),

MoneyColumn::make('price')
    ->currency('EUR')
    ->locale('it_IT'),

Prior to v5.0.4 the table column did not accept currency/locale, so formatted output in tables had to fall back to the global config or a manual formatStateUsing(). With v5.0.4 you can format per-column, which is what makes the package usable in a multi-currency admin panel.

Implementation Patterns

Let config carry the default, override at the edge. Put your primary currency/locale in the config file, then only pass ->currency() / ->locale() where a record genuinely differs. This keeps resources readable and makes a future currency switch a one-line change.

Multi-currency per record. The common real-world shape is a price + currency column pair. Read the currency off the record rather than hard-coding it:

MoneyInput::make('price')
    ->currency(fn ($record) => $record?->currency ?? 'EUR')
    ->locale(fn () => app()->getLocale()),

MoneyColumn::make('price')
    ->currency(fn ($record) => $record->currency)
    ->locale(fn () => app()->getLocale()),

Because v5.0.4 added currency/locale support to the table column, the form and the table can now be driven by the same closures — previously the table would silently format in the default currency and disagree with the form.

Keep brick/money as the domain layer. Treat the Filament components as pure UI. Cast the persisted value to a Brick\Money\Money on your Eloquent model (a custom cast or an accessor) and do arithmetic, allocation and conversions there. The field should never be the place where money math happens.

Locale is presentation, not data. Store one canonical representation and vary locale for display only. If you support it_IT (comma decimal) and en_US (dot decimal), the same underlying value should format both ways without any migration.

Testing. Filament form/table components are Livewire-backed; use livewire()->fillForm([...])->call('save') and assert against the persisted raw value rather than the formatted string. For the column, assertTableColumnFormattedStateSet() is the assertion that catches locale regressions.

Upgrade posture for v5.0.4. This is a patch release: one feature (currency and locale on the table component), a CHANGELOG update and a styling pass. No migrations, no signature changes, no deprecations. Update with confidence.

Gotchas and Tips

  • Currency and locale are independent and both matter. ->currency('EUR')->locale('en_US') renders €1,234.56; the reverse ordering of assumptions produces 1.234,56 €. Decide the pair deliberately, and set the locale explicitly in the column now that v5.0.4 allows it — a mismatch between form and table is the number-one bug report for packages like this.
  • Input parsing vs. display formatting. Users type localised separators. Verify how MoneyInput parses a comma decimal against your locale before going live; if you accept free text, add a validation rule so a mis-typed value fails loudly instead of being silently reinterpreted as thousands.
  • Agree on your storage unit. Integer minor units (cents) is the safe choice; if you store decimals, keep the scale fixed (e.g. decimal(12,2)) and never widen it loosely. Getting this wrong is expensive to fix once rows exist.
  • null and 0 are not the same in a table. An empty column cell should read as a dash, not €0.00. Use the column's placeholder/empty-state option rather than a formatStateUsing() closure that coerces nulls.
  • Changing currency on existing rows does not convert anything. It changes labels. If you need conversion, do it as an explicit migration with a recorded FX rate.
  • Global config is a fallback, not a constraint. Per-field and per-column arguments always win, so a stray config publish cannot silently override a field that sets its own currency — but a field that omits it will follow the config.
  • Extension point. If you need custom formatting rules that brick/money's MoneyFormatter can't express, subclass MoneyColumn and override the formatting method rather than reaching into the base component's internals.
  • Debugging tip. When a value renders oddly, dump the raw model attribute first ($record->getRawOriginal('price')) to confirm whether the problem is storage, casting, or formatting — the component sits at the end of that chain and is rarely the culprit.
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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource