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

Nova Text Currency Laravel Package

lathanhvien/nova-text-currency

A Laravel Nova field for entering and displaying monetary values as formatted text, making currency input simple in your admin panels. Add it to Nova resources for a lightweight text-based currency field.

View on GitHub
Deep Wiki
Context7

Getting Started

This is the initial v1.0.0 release, adding two capabilities that matter for money and quantity fields: dynamic input with thousand separators and currency symbol support.

  1. Install the package with Composer and publish any config/assets if the package ships them:
    composer require <vendor>/<package>
    php artisan vendor:publish --tag=<package>-config
    
  2. Look first at the config file. This is where separator, decimal, and currency-symbol defaults normally live. Confirm:
    • thousand separator (, vs . vs space)
    • decimal separator (. vs ,)
    • decimal precision
    • default currency symbol and whether it renders before or after the value
  3. First use case: a price/amount field in a create/edit form. The input should format live as the user types — e.g. typing 1234567 becomes 1,234,567 or $1,234,567.00 — while the value you validate and persist remains a plain numeric string.

A reasonable first integration looks like:

<form method="POST" action="{{ route('products.store') }}">
    @csrf
    <x-dynamic-input
        name="price"
        currency="USD"
        :decimals="2"
    />
    @error('price') <span>{{ $message }}</span> @enderror
    <button type="submit">Save</button>
</form>

Before wiring it into a real form, verify what the component actually submits — formatted text ($1,234.56) or a normalized value (1234.56). That single detail drives most of the implementation patterns below.

Implementation Patterns

Normalize on the server, always

Treat the browser formatting as presentation only. Strip currency symbols, thousand separators, and non-breaking spaces before validation and before writing to the database:

$raw = $request->input('price');           // "$1,234.56"
$normalized = str_replace(
    ['$', ',', "\u{00A0}", ' '],
    '',
    $raw
);                                          // "1234.56"

$request->merge(['price' => $normalized]);

$validated = $request->validate([
    'price' => ['required', 'numeric', 'min:0'],
]);

If the package exposes a formatter/normalizer helper or cast, use that instead of hand-rolled str_replace so behaviour stays consistent with the input component.

Blade usage

Use the component for both create and edit forms. On edit, seed it with the raw numeric value, not the pre-formatted string, and let the component handle display formatting:

<x-dynamic-input
    name="price"
    :value="old('price', $product->price)"
    currency="USD"
    :decimals="2"
/>

Use the same config/currency source for display in index and show views so the formatted input and the read-only output agree.

Livewire binding

Bind with wire:model and normalize in updated hooks or in a computed accessor. Because formatted input changes on every keystroke, prefer deferred updates (wire:model.blur or wire:model.defer) unless you genuinely need live recalculation:

<x-dynamic-input
    name="price"
    wire:model.blur="price"
    currency="USD"
/>
public function updatedPrice($value): void
{
    $this->price = $this->normalizeMoney($value);
}

Multi-currency and locale

Drive the symbol and separators from config or the user's locale rather than hard-coding them in markup. A single config default plus per-instance overrides covers most cases:

<x-dynamic-input name="price" :currency="config('shop.currency')" />
<x-dynamic-input name="price" currency="EUR" locale="de" />

Validation and persistence

  • Validate the normalized value, not the formatted one.
  • Store as decimal/integer columns, never as formatted strings.
  • Keep formatting logic in one place (the package component or a small formatter service) so API responses, exports, and PDFs render consistently.

Gotchas and Tips

  • Thousand separators break numeric validation. A posted value of 1,234.56 fails Laravel's numeric rule. Normalize before validation, or add a custom rule that strips separators first.
  • Locale separator ambiguity. In many locales 1.234,56 means one thousand two hundred thirty-four. Do not assume , is always a thousands separator. Make the separator explicit in config and test at least one comma-decimal locale.
  • Currency symbol round-tripping. If the symbol is rendered inside the <input> value, it will be submitted with the form. Either render the symbol as a separate prefix/suffix element outside the input, or strip it server-side. Confirm which approach the component takes in v1.0.0.
  • Cursor jumping. Re-formatting on every keystroke can move the caret to the end. Test editing mid-string. Prefer format-on-blur or a library that preserves caret position if the component offers it.
  • Livewire re-render loops. Formatting inside updated hooks can trigger another update cycle. Guard against re-normalizing an already-normalized value and compare before assigning.
  • Dynamically added rows. If you clone form rows (e.g. invoice line items), re-initialize any JS behaviour on the new elements. Delegated event listeners or a component init hook avoid dead inputs.
  • Empty and partial input. Handle "", "-", "$", and "." without throwing. Decide whether empty normalizes to null or 0 and be consistent with your database defaults.
  • Extension points to check first: published Blade views (for markup/symbol placement), the config file (separators, precision, default currency), and any formatter/normalizer class or cast the package exposes. Prefer overriding these over patching vendor files.
  • Since this is v1.0.0, pin the version and add a feature test that asserts the round trip: formatted input → normalized request value → persisted decimal → formatted display. That test will catch breaking changes in future releases quickly.
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