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 Advanced Number Field Laravel Package

simplesquid/nova-advanced-number-field

An advanced number field for Laravel Nova that adds flexible formatting, min/max limits, step controls, and locale-aware display to numeric inputs, making it easy to build polished, precise forms for prices, quantities, and other numbers.

View on GitHub
Deep Wiki
Context7

Getting Started

Confirm the platform floor before writing a line of field config. v3.3.0 is the first release on Nova 5 and Laravel 12, and it drops PHP 8.1 and Laravel 10. Check composer.json for laravel/nova and the PHP constraint first; if the app is still on Nova 4 or PHP 8.1, stop and stay on the last 3.2.x — do not let this package drive a platform upgrade.

composer require simplesquid/nova-advanced-number-field:^3.3

Pin the constraint explicitly. A floating ^3.0 lets a routine composer update cross the support floor silently, which surfaces later as a confusing Nova boot failure rather than a dependency error.

If Composer resolution fails unexpectedly, it is probably Nova auth. Nova lives in a private repository, and bad credentials come back as a generic conflict. Diagnose with:

composer why-not simplesquid/nova-advanced-number-field ^3.3
composer why-not laravel/nova ^5.0

and verify auth.json / COMPOSER_AUTH holds valid nova.laravel.com credentials.

Read the source first, README second. The package is one field class plus a compiled Vue component. Before writing any config, confirm the class and its available methods:

grep -rn "class Number" vendor/simplesquid/nova-advanced-number-field/src
grep -rn "public function" vendor/simplesquid/nova-advanced-number-field/src

The second grep is your real API reference — the documented surface is decimals, prefix, suffix, min, max, step, but confirm signatures rather than assuming.

First use case: swap exactly one field, verify all three surfaces. Pick a resource that already uses Nova's native Number and convert it. Do not refactor anything else in the same PR.

use Simplesquid\NovaAdvancedNumberField\Number; // verify from the grep above

Number::make('Price')
    ->min(0)
    ->max(1000000)
    ->step(0.01)
    ->decimals(2)
    ->prefix('$')
    ->sortable()
    ->rules('required', 'numeric', 'min:0'),

Check index, detail, and form views in staging. If the formatted input does not render, revert and keep native Nova — the incremental value is presentation, not validation.

Implementation Patterns

Duplicate every constraint into ->rules(). min, max, and step are client-side affordances on the input. Nothing stops a crafted POST.

Number::make('Discount %', 'discount_percent')
    ->min(0)->max(100)->step(0.1)->suffix('%')
    ->rules('required', 'numeric', 'between:0,100'),

Make the column, the cast, and the field precision agree. The field formats; it does not change what is stored.

// migration
$table->decimal('price', 10, 2);

// model
protected $casts = ['price' => 'decimal:2'];

// Nova
Number::make('Price')->decimals(2)->prefix('$')

A decimal(10,4) column displayed at two decimals will accept 12.3456 and show 12.35 — invisible rounding that only appears at reconciliation. Never store money as float; formatting cannot repair floating-point arithmetic. Use integer minor units or a decimal cast.

Centralise the field definitions on day one. You will otherwise hand-copy the same five chained calls across a dozen resources and miss one when a currency or precision requirement changes. A subclass is the cheapest hedge:

// app/Nova/Fields/MoneyNumber.php
class MoneyNumber extends \Simplesquid\NovaAdvancedNumberField\Number
{
    public function __construct($name, $attribute = null, $resolveCallback = null)
    {
        parent::__construct($name, $attribute, $resolveCallback);
        $this->min(0)->step(0.01)->decimals(2)->prefix('$');
    }
}

This also means most of your resources never reference the vendor namespace directly — see the vendor-risk note below.

Configure per intent, not globally. Resist one "number" preset; the constraints are genuinely different:

// Percentage
MoneyNumber::make('Rate')->max(100)->suffix('%')->rules('numeric', 'between:0,100')

// Quantity — integer rule prevents half-unit stock rows
Number::make('Stock', 'stock')->decimals(0)->step(1)->min(0)->rules('integer', 'min:0')

// Computed value shown on index/detail only
Number::make('Total')->decimals(2)->prefix('$')->onlyOnIndex()->onlyOnDetail()

Sorting and filtering are unaffected — as long as you store raw numbers. Nova sorts and filters on the column, not the rendered string. The failure mode is storing the formatted value ("$1,234.00") into the database, which breaks sorting, filtering, exports, and everything downstream. Format only at render time, which is exactly what this field does.

Keep one canonical formatter outside Nova. The field formats inside the admin panel and nowhere else — not APIs, not PDF invoices, not exports. Put the source of truth in a shared place (a Money value object, Number::currency()) and let this field be one view of it. If admin and invoices must agree to the cent, the shared formatter is the contract, not the field config.

Test the PHP config, budget manual QA for the Vue layer. You can assert serialization without a browser:

$field = MoneyNumber::make('Price');
$meta  = $field->jsonSerialize();
$this->assertSame(2, $meta['decimals'] ?? null);
$this->assertSame('$', $meta['prefix'] ?? null);

The rendered component is not covered by PHPUnit. Dusk or a manual pass on every Nova major is the real ongoing cost — plan for it in whatever ticket tracks Nova upgrades.

Gotchas and Tips

Stale compiled assets are the most common Nova failure, and they mimic field bugs. The package ships prebuilt JS; Nova republishes on upgrade. After any Composer or Nova bump:

php artisan nova:publish
php artisan optimize:clear
# if you own custom tools/cards:
npm ci && npm run prod

A blank or unstyled numeric input that "works locally, breaks in staging" is almost always this. Check the network payload for the field's meta before debugging PHP.

prefix()/suffix() are static decoration, not locale formatting. prefix('$') is a string. Do not expect 1.234,56 € because the app locale is de. For a multi-locale admin, either accept a fixed presentation or wrap the logic yourself.

Native number inputs behave differently across browsers, particularly on step validation, scroll-wheel changes, and decimal marks. If a value "can't be typed" but saves fine (or the reverse), the browser is the variable — test in the browsers your operators actually use, and lean on ->rules().

Debug a non-rendering field in this order:

  1. Is the namespace import correct and the class resolving? (grep -rn "class Number" src)
  2. Does jsonSerialize() contain your config?
  3. Does the resource's JSON response carry the expected component name?
  4. Does that component exist in the published assets?

The bug is at one of those four steps and essentially never in the numeric logic.

Hedge vendor risk proportionately. Eleven stars, zero dependents, single maintainer — real bus factor, bounded blast radius. The mitigation is: subclass the field so usage points at your class, keep the version pinned, and accept that absorbing one class into app/Nova/Fields is an afternoon if the project goes dormant. That only stays cheap if you have not sprayed the vendor namespace across fifty resources.

Don't add the dependency for validation alone. Nova's native Number already does min/max/step. The defensible reasons to take this on are decimal precision control, prefix/suffix clarity, and consistent rendering between form and detail views. If none of those is the actual requirement, keep native and close the ticket.

Don't reach for it outside Nova. It does nothing for API responses, imports, or exports. When the requirement is "numbers look right everywhere," this covers roughly one surface — be explicit about that split rather than letting someone assume it is global.

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.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo