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

gekich/nova-range-filter

A Laravel Nova filter package that adds range-based filtering to Nova resources, letting users narrow records by numeric or date ranges from the filter panel. A small, low-adoption add-on for simple interval filtering in admin panels.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install into a Nova v3+ app:
    composer require gekich/nova-range-filter
    
  2. If the package ships a custom Vue component, publish/rebuild Nova assets so the range inputs render:
    php artisan vendor:publish --tag=nova-range-filter-assets
    php artisan nova:publish
    
  3. Scaffold a filter and switch its parent class to the package's range filter:
    php artisan nova:filter PriceRange
    
    use Gekich\NovaRangeFilter\RangeFilter; // verify exact namespace in src/
    
    class PriceRange extends RangeFilter
    {
        public $name = 'Price Range';
    
        public function column(): string
        {
            return 'price';
        }
    }
    
  4. Register it on the resource:
    public function filters(Request $request)
    {
        return [new PriceRange];
    }
    

Where to look first: src/ for the base filter class (this is the entire API surface — typically a $column, an apply() doing whereBetween, and a key()/options() stub) and resources/js/ for the range component that defines how the min/max value is serialized. Read the base class before writing any filter — there is almost no documentation to fall back on.

First use case: a numeric min/max on a single indexed column (price, quantity, age). Dates are the second use case but need more care (see Gotchas).

Implementation Patterns

Numeric range on a local column — the intended happy path:

class PriceRange extends RangeFilter
{
    public $name = 'Price';

    public function column(): string { return 'price'; }
}

Date range — override apply() rather than relying on whereBetween against a datetime column, so the upper bound includes the whole day:

public function apply(Request $request, $query, $value)
{
    [$from, $to] = [$value['min'] ?? null, $value['max'] ?? null];

    return $query
        ->when($from, fn ($q) => $q->whereDate('created_at', '>=', $from))
        ->when($to,   fn ($q) => $q->whereDate('created_at', '<=', $to));
}

Relation / qualified columns — the base class usually passes the column straight into whereBetween, so give it the qualified name to avoid ambiguity:

public function column(): string { return 'orders.total'; }

and ensure the relationship is joined before the filter runs.

Default range — implement default() to pre-fill the inputs so the filter is visible in the URL and active on first load:

public function default()
{
    return ['min' => null, 'max' => null];
}

Reuse across resources — because the column is the only real variable, build one generic filter with a constructor argument and instantiate it per resource:

class NumericRange extends RangeFilter
{
    public function __construct(public string $column, public ?string $label = null) {}

    public function column(): string { return $this->column; }
}
// filters(): [new NumericRange('price', 'Price'), new NumericRange('stock', 'Stock')]

Stacking with other filters — nothing special is required; Nova applies each filter's apply() in sequence. Keep the range filter narrow (one column) so it composes cleanly with search and relationship filters.

Testing — Nova filters are plain classes, so unit-test apply() directly against a query builder with a fake Request; you don't need HTTP tests or a browser.

Gotchas and Tips

  • The package is archived with a single star. Treat it as a reference implementation, not a dependency. Vendor/fork it, or copy the ~30 lines of apply() into your own Filter subclass. There will be no fixes for Nova version drift.
  • Nova 4/5 compatibility is unlikely out of the box. The filter base class, Nova::script() registration, and the Vue component API all changed after v3. Check composer.json constraints and the component's mixins/Form usage before installing on anything newer than v3.
  • Assets don't load automatically. A custom filter component only renders if its JS is registered and built. Symptom: the filter appears with a blank body or a raw text input. Fix with nova:publish + npm run dev/prod in the host app.
  • The $value shape is an array with possible nulls. Both min and max may be empty strings or null when only one side is filled. Always guard before whereBetween — passing [null, null] silently returns zero rows on some drivers.
  • Datetime columns truncate the upper bound. whereBetween('created_at', ['2024-01-01', '2024-01-31']) excludes everything after 00:00:00 on the 31st. Use whereDate, or append 23:59:59, or use an exclusive < nextDay bound.
  • Filter state lives in the query string. Nova serializes the filter value via key(); renaming the filter class or changing the value shape breaks bookmarked URLs and silently drops the filter. Keep the class name stable.
  • Debugging: dd($value) at the top of apply() is the fastest way to see what the component actually sends. If apply() never fires, the issue is asset registration; if it fires with the wrong data, the issue is the Vue component's value handling.
  • Extension points are thin by design — the useful override seams are apply(), default(), key(), and column(). Anything more elaborate (presets, "last 30 days" shortcuts) belongs in your own filter class rather than in a subclass of this one.
  • Indexes matter more here than usual. Range filters on unindexed columns are the most common cause of slow Nova index pages; confirm the column is indexed before shipping the filter to users.
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.
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table
siberfx/flysystem-wasabi
hollyit/token-replace
ippanelcom/laravel-sdk
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel