PHPackages                             dev-jm/nova-dependent-filter - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Search &amp; Filtering](/categories/search)
4. /
5. dev-jm/nova-dependent-filter

ActiveLibrary[Search &amp; Filtering](/categories/search)

dev-jm/nova-dependent-filter
============================

Cascading/dependent select filters for Laravel Nova 5.

v1.0.1(3mo ago)05MITJavaScriptPHP ^8.1

Since Feb 14Pushed 3mo agoCompare

[ Source](https://github.com/Jenry-MA/nova-dependent-filter)[ Packagist](https://packagist.org/packages/dev-jm/nova-dependent-filter)[ RSS](/packages/dev-jm-nova-dependent-filter/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (1)Dependencies (1)Versions (4)Used By (0)

Nova Dependent Filter
=====================

[](#nova-dependent-filter)

Cascading/dependent select filters for Laravel Nova 5. When a user selects a value in a **parent** filter, the **child** filter automatically narrows its options.

Demo
----

[](#demo)

[![Demo](docs/screenshots/example.gif)](docs/screenshots/example.gif)

In this example, selecting the client **INTLXS** automatically narrows the **Project** filter to only show projects that belong to that client. Then, selecting a project narrows the **User** filter to only show users assigned to that specific project. Clearing a parent filter resets its children back to showing all available options.

---

Installation
------------

[](#installation)

Install via Composer:

```
composer require dev-jm/nova-dependent-filter
```

The package auto-registers its service provider via Laravel's package discovery.

---

Quick Start
-----------

[](#quick-start)

```
use DevJM\DependentFilter\Nova\Filters\DependentFilter;
use App\Models\Client;
use App\Models\Project;
use App\Models\User;

public function filters(NovaRequest $request)
{
    $client = DependentFilter::make('Client', Client::class, 'client_id');

    $project = DependentFilter::make('Project', Project::class, 'project_id')
        ->dependsOn($client, foreignKey: 'client_id');

    $user = DependentFilter::make('User', User::class, 'user_id')
        ->dependsOn($project, relationship: 'projects');

    return [$client, $project, $user];
}
```

That's it. Three lines, three cascading filters.

---

How It Works
------------

[](#how-it-works)

1. **Page loads** - all filters show their full list of options.
2. **User picks a Client** - the Project dropdown re-fetches and only shows projects belonging to that client.
3. **User picks a Project** - the User dropdown re-fetches and only shows users assigned to that project.
4. **User clears a parent** - child filters reset and go back to showing all options.

---

API Reference
-------------

[](#api-reference)

### `DependentFilter::make(name, model, column)`

[](#dependentfiltermakename-model-column)

Creates a new filter instance.

ArgumentTypeDescription`name``string`Display name shown in the filter panel`model``string`Eloquent model class used to fetch options`column``string`Column on the **resource table** to filter by (e.g. `project_id`)```
DependentFilter::make('Project', Project::class, 'project_id')
```

---

### `->dependsOn($parentFilter, foreignKey: ..., relationship: ...)`

[](#-dependsonparentfilter-foreignkey--relationship-)

Declares that this filter's options depend on another filter's selected value. Use **one** of the two named arguments:

#### Option A: `foreignKey` (for belongsTo / direct column)

[](#option-a-foreignkey-for-belongsto--direct-column)

When the child model has a foreign key column pointing to the parent.

```
Client (id) dependsOn($client, foreignKey: 'client_id');
```

This generates: `Project::where('client_id', $selectedClientId)`

#### Option B: `relationship` (for belongsToMany / hasMany)

[](#option-b-relationship-for-belongstomany--hasmany)

When the child model is connected to the parent through an Eloquent relationship.

```
Project  User  (pivot table: project_user)

```

```
$user = DependentFilter::make('User', User::class, 'user_id')
    ->dependsOn($project, relationship: 'projects');
```

This generates: `User::whereHas('projects', fn($q) => $q->where('id', $selectedProjectId))`

> The `relationship` value must match the **Eloquent relationship method name** on the child model (e.g. `User::projects()`).

---

### `->scope(fn($query, $request) => ...)`

[](#-scopefnquery-request--)

Adds a base query scope applied to **both** the initial options and the dependent (filtered) options. Use this for permission checks, active status, or any global filtering.

```
// Only show active users with roles
$user = DependentFilter::make('User', User::class, 'user_id')
    ->scope(fn ($query) => $query->whereHas('roles')->where('is_active', 1));

// Permission-based scoping
$project = DependentFilter::make('Project', Project::class, 'project_id')
    ->scope(function ($query, $request) {
        if ($request->user()->hasPermissionTo('viewAllProjects')) {
            // no restriction
        } else {
            $query->whereHas('users', fn ($q) => $q->where('users.id', $request->user()->id));
        }
    });
```

> The callback receives `($query, $request)`. The second argument `$request` is optional - omit it if you don't need it.

---

### `->label(column)` and `->value(column)`

[](#-labelcolumn-and--valuecolumn)

Customize which model columns are used for the dropdown label and value.

MethodDefaultDescription`->label()``'name'`Column shown as the dropdown text`->value()``'id'`Column sent as the selected value```
DependentFilter::make('Country', Country::class, 'country_code')
    ->label('full_name')
    ->value('iso_code');
```

---

Examples
--------

[](#examples)

### Standalone filter (no dependencies)

[](#standalone-filter-no-dependencies)

Works like a regular Nova select filter - no cascading, just a cleaner syntax.

```
DependentFilter::make('Status', Status::class, 'status_id')
```

### Two-level cascade

[](#two-level-cascade)

```
$department = DependentFilter::make('Department', Department::class, 'department_id');

$employee = DependentFilter::make('Employee', Employee::class, 'employee_id')
    ->dependsOn($department, foreignKey: 'department_id')
    ->scope(fn ($q) => $q->where('is_active', true));

return [$department, $employee];
```

### Three-level cascade

[](#three-level-cascade)

```
$country = DependentFilter::make('Country', Country::class, 'country_id');

$city = DependentFilter::make('City', City::class, 'city_id')
    ->dependsOn($country, foreignKey: 'country_id');

$office = DependentFilter::make('Office', Office::class, 'office_id')
    ->dependsOn($city, foreignKey: 'city_id');

return [$country, $city, $office];
```

### Conditional inclusion

[](#conditional-inclusion)

```
$client = DependentFilter::make('Client', Client::class, 'client_id');

$project = DependentFilter::make('Project', Project::class, 'project_id')
    ->dependsOn($client, foreignKey: 'client_id');

if ($request->user()->isClient()) {
    return [$project];
} else {
    return [$client, $project];
}
```

### Mixed with regular Nova filters

[](#mixed-with-regular-nova-filters)

```
return [
    (new StartsDateFilter())->setColumn('start'),
    (new EndsDateFilter())->setColumn('start'),
    $clientFilter,
    new TimeTrackingDepartmentFilter(),
    $projectFilter,
    $userFilter,
];
```

License
-------

[](#license)

MIT

###  Health Score

36

—

LowBetter than 82% of packages

Maintenance82

Actively maintained with recent releases

Popularity4

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity45

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

2

Last Release

93d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/e082682f1cdd0d08bd8273bf77e5aff4cf5dac557091172c4e0d5aa39ebe0635?d=identicon)[dev-jm](/maintainers/dev-jm)

---

Top Contributors

[![Jenry-MA](https://avatars.githubusercontent.com/u/13290876?v=4)](https://github.com/Jenry-MA "Jenry-MA (6 commits)")

---

Tags

laravelfilternovadependentcascading

### Embed Badge

![Health badge](/badges/dev-jm-nova-dependent-filter/health.svg)

```
[![Health](https://phpackages.com/badges/dev-jm-nova-dependent-filter/health.svg)](https://phpackages.com/packages/dev-jm-nova-dependent-filter)
```

###  Alternatives

[outl1ne/nova-multiselect-filter

Multiselect filter for Laravel Nova.

45802.7k3](/packages/outl1ne-nova-multiselect-filter)[outl1ne/nova-detached-filters

This Laravel Nova package allows you to detach filters from the filter dropdown

64343.5k](/packages/outl1ne-nova-detached-filters)[digital-creative/nova-mega-filter

Allows you to control the columns and filters shown on your nova resources.

87159.3k](/packages/digital-creative-nova-mega-filter)[optimistdigital/nova-detached-filters

This Laravel Nova package allows you to detach filters from the filter dropdown

64235.5k](/packages/optimistdigital-nova-detached-filters)[outl1ne/nova-input-filter

An input filter for Laravel Nova

24822.7k](/packages/outl1ne-nova-input-filter)[suenerds/nova-searchable-belongs-to-filter

Searchable Nova filter for belongsTo relationships.

29516.9k](/packages/suenerds-nova-searchable-belongs-to-filter)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
