PHPackages                             codewithdennis/filament-select-tree - 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. [Utility &amp; Helpers](/categories/utility)
4. /
5. codewithdennis/filament-select-tree

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

codewithdennis/filament-select-tree
===================================

The multi-level select field enables you to make single selections from a predefined list of options that are organized into multiple levels or depths.

v4.2.1(2w ago)329530.5k↓29.4%54[2 issues](https://github.com/CodeWithDennis/filament-select-tree/issues)[3 PRs](https://github.com/CodeWithDennis/filament-select-tree/pulls)17MITPHPPHP ^8.2CI passing

Since Sep 17Pushed 1w ago4 watchersCompare

[ Source](https://github.com/CodeWithDennis/filament-select-tree)[ Packagist](https://packagist.org/packages/codewithdennis/filament-select-tree)[ Docs](https://github.com/codewithdennis/filament-select-tree)[ GitHub Sponsors](https://github.com/CodeWithDennis)[ RSS](/packages/codewithdennis-filament-select-tree/feed)WikiDiscussions 4.x Synced 2d ago

READMEChangelog (10)Dependencies (40)Versions (96)Used By (17)

Filament Select Tree
====================

[](#filament-select-tree)

[![Latest Version on Packagist](https://camo.githubusercontent.com/a6c1bed8af3fcd3037a7ac8f4f06b05ef65ef2879d43c13cabbb5b8e96a766a9/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f636f64657769746864656e6e69732f66696c616d656e742d73656c6563742d747265652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/codewithdennis/filament-select-tree)[![Total Downloads](https://camo.githubusercontent.com/af431823329515f811c4cea866605e5f434fd6825695186d6fe89d4fc94aa505/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f636f64657769746864656e6e69732f66696c616d656e742d73656c6563742d747265652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/codewithdennis/filament-select-tree)

If you're using Filament 3.x, check out the compatible version of this package [here](https://github.com/CodeWithDennis/filament-select-tree/tree/3.x).

This package adds a dynamic select tree field to your Laravel / Filament application, allowing you to create interactive hierarchical selection dropdowns based on relationships. It's handy for building selection dropdowns with various customization options.

[![thumbnail](https://raw.githubusercontent.com/CodeWithDennis/filament-select-tree/3.x/resources/images/thumbnail.jpg)](https://raw.githubusercontent.com/CodeWithDennis/filament-select-tree/3.x/resources/images/thumbnail.jpg)

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

[](#installation)

You can install the package via composer:

```
composer require codewithdennis/filament-select-tree:4.x
```

```
php artisan filament:assets
```

Relationships
-------------

[](#relationships)

Use the tree for a `BelongsToMany` relationship

```
SelectTree::make('categories')
    ->relationship('categories', 'name', 'parent_id')
```

Use the tree for a `BelongsTo` relationship

```
SelectTree::make('category_id')
    ->relationship('category', 'name', 'parent_id')
```

Usage without relationships
---------------------------

[](#usage-without-relationships)

Use the tree without relationship

```
SelectTree::make('category_id')
    ->query(fn() => Category::query(), 'name', 'parent_id')
```

Custom Query
------------

[](#custom-query)

Customize the parent query

```
SelectTree::make('categories')
    ->relationship(relationship: 'categories', titleAttribute: 'name', parentAttribute: 'parent_id', modifyQueryUsing: fn($query) => $query));
```

Customize the child query

```
SelectTree::make('categories')
    ->relationship(relationship: 'categories', titleAttribute: 'name', parentAttribute: 'parent_id', modifyChildQueryUsing: fn($query) => $query));
```

Note: when you filter the parent query, any results found by the child query whose parents have been filtered out will be promoted to root nodes by default (to prevent empty result sets). To disable this feature, use the `strictNullParentRootNodes()` configuration method

```
SelectTree::make('categories')
    ->relationship(relationship: 'categories', titleAttribute: 'name', parentAttribute: 'parent_id', modifyQueryUsing: fn($query) => $query->where('id', 1))
    ->strictNullParentRootNodes(); // only children of parent results from the parent query will be included in the tree
```

Methods
-------

[](#methods)

Set a custom placeholder when no items are selected

```
->placeholder(__('Please select a category'))
```

Enable the selection of groups

```
->enableBranchNode()
```

Customize the label when there are zero search results

```
->emptyLabel(__('Oops, no results have been found!'))
```

Display the count of children alongside the group's name

```
->withCount()
```

Keep the dropdown open at all times

```
->alwaysOpen()
```

Add the list as a static DOM element so that it doesn't overlap content

```
->staticList()
```

Set nodes as dependent

```
->independent(false)
```

Expand the tree with selected values (only works if field is dependent)

```
->expandSelected(false)
```

Set the parent's null value to -1, allowing you to use -1 as a sentinel value (default = null)

```
->parentNullValue(-1)
```

All groups will be opened to this level

```
->defaultOpenLevel(2)
```

Specify the list's force direction. Options include: auto (default), top, and bottom.

```
->direction('top')
```

Display individual leaf nodes instead of the main group when all leaf nodes are selected

```
->grouped(false)
```

Return parent node value if all of its children are selected, instead of individual leaf nodes.

```
->isGroupedValue()
```

Hide tags and display a count of selected items instead

```
->showTags(false)
```

Customize the text shown if `showTags` is set to `false`, e.g. "{count} {tagsCountText}"

```
->tagsCountText('elements selected')
```

Hide the clearable icon

```
->clearable(false)
```

Activate the search functionality

```
->searchable();
```

Disable specific options in the tree

```
->disabledOptions([2, 3, 4])
```

Hide specific options in the tree

```
->hiddenOptions([2, 3, 4])
```

Allow soft deleted items to be displayed

```
->withTrashed()
```

Specify a different key for your model. For example: you have id, code and parent\_code. Your model uses id as key, but the parent-child relation is established between code and parent\_code

```
->withKey('code')
```

Store fetched models for additional functionality

```
->storeResults()
```

Now you can access the results in `disabledOptions` or `hiddenOptions`

```
->disabledOptions(function ($state, SelectTree $component) {
    $results = $component->getResults();
})
```

By default, the type of selection in the tree (single or multiple) is determined by the relationship type: `BelongsTo` for single selection and `BelongsToMany` for multiple selection. If you want to explicitly set the selection type, use:

```
->multiple(false)
```

you can change the tree key with the following method.

```
->treeKey('my-cool-tree')
```

If you need to prepend an item to the tree menu, use the `prepend` method. This method accepts an array or a closure. It is useful when the tree-select is used as a filter (see example below).

```
use Filament\Tables\Filters\Filter;
use Illuminate\Database\Eloquent\Builder;
use CodeWithDennis\FilamentSelectTree\SelectTree;
```

```
->filters([
    Filter::make('tree')
        ->form([
            SelectTree::make('category')
                ->relationship('categories', 'name', 'parent_id')
                ->enableBranchNode()
                ->multiple(false)
                ->prepend([
                    'name' => 'Uncategorized Records',
                    'value' => -1,
                    'parent' => null, // optional
                    'disabled' => false, // optional
                    'hidden' => false, // optional
                    'children' => [], // optional
                ])
        ])
        ->query(function (Builder $query, array $data) {
            return $query->when($data['categories'], function (Builder $query, $categories) {
                if (collect($categories)->contains('-1')) {
                    $query->whereDoesntHave('categories');
                }
                return $query->orWhereHas('categories',
                    fn(Builder $query) => $query->whereIn('id', $categories));
            });
        })
])
```

If you need to append an item to the tree menu, use the `append` method. This method also accepts an array or a closure.

```
->schema([
    SelectTree::make('category')
        ->relationship('categories', 'name', 'parent_id')
        ->enableBranchNode()
        ->multiple(false)
        ->append([
            'name' => 'Uncategorized Records',
            'value' => -1,
            'parent' => null, // optional
            'disabled' => false, // optional
            'hidden' => false, // optional
            'children' => [], // optional
        ])
    ])
```

If you need full control over the tree structure, you can use `getTreeUsing` to provide a custom tree array, or a closure that resolves to an array.

Using an array:

```
SelectTree::make('categories')
    ->getTreeUsing([
        [
            'name' => 'Parent Category',
            'value' => '1',
            'children' => [
                [
                    'name' => 'Child Category',
                    'value' => '2',
                    'children' => [],
                ],
            ],
        ],
        [
            'name' => 'Another Category',
            'value' => '3',
            'children' => [],
        ],
    ])
```

Using a closure for dynamic data:

```
SelectTree::make('categories')
    ->getTreeUsing(function () {
        return Category::query()
            ->get()
            ->map(fn ($category) => [
                'name' => $category->name,
                'value' => $category->id,
                'children' => $category->children->map(fn ($child) => [
                    'name' => $child->name,
                    'value' => $child->id,
                    'children' => [],
                ])->toArray(),
            ])
            ->toArray();
    })
```

The tree structure should follow this format:

```
[
    [
        'name' => 'Display Name',
        'value' => 'option_value',
        'disabled' => false, // optional
        'hidden' => false, // optional
        'children' => [], // optional
    ],
]
```

Filters
-------

[](#filters)

Use the tree in your table filters. Here's an example to show you how.

```
use Filament\Tables\Filters\Filter;
use Illuminate\Database\Eloquent\Builder;
use CodeWithDennis\FilamentSelectTree\SelectTree;
```

```
->filters([
    Filter::make('tree')
        ->form([
            SelectTree::make('categories')
                ->relationship('categories', 'name', 'parent_id')
                ->independent(false)
                ->enableBranchNode(),
        ])
        ->query(function (Builder $query, array $data) {
            return $query->when($data['categories'], function ($query, $categories) {
                return $query->whereHas('categories', fn($query) => $query->whereIn('id', $categories));
            });
        })
        ->indicateUsing(function (array $data): ?string {
            if (! $data['categories']) {
                return null;
            }

            return __('Categories') . ': ' . implode(', ', Category::whereIn('id', $data['categories'])->get()->pluck('name')->toArray());
        })
])
```

Screenshots
-----------

[](#screenshots)

[![example-1](https://raw.githubusercontent.com/CodeWithDennis/filament-select-tree/3.x/resources/images/example-1.jpg)](https://raw.githubusercontent.com/CodeWithDennis/filament-select-tree/3.x/resources/images/example-1.jpg)[![example-2](https://raw.githubusercontent.com/CodeWithDennis/filament-select-tree/3.x/resources/images/example-2.jpg)](https://raw.githubusercontent.com/CodeWithDennis/filament-select-tree/3.x/resources/images/example-2.jpg)[![example-3](https://raw.githubusercontent.com/CodeWithDennis/filament-select-tree/3.x/resources/images/example-3.jpg)](https://raw.githubusercontent.com/CodeWithDennis/filament-select-tree/3.x/resources/images/example-3.jpg)

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](.github/CONTRIBUTING.md) for details.

Security Vulnerabilities
------------------------

[](#security-vulnerabilities)

Please review [our security policy](../../security/policy) on how to report security vulnerabilities.

Credits
-------

[](#credits)

- [CodeWithDennis](https://github.com/CodeWithDennis) / [Website](https://codewithdennis.com)
- [Dipson88](https://github.com/dipson88/treeselectjs)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

69

—

FairBetter than 100% of packages

Maintenance97

Actively maintained with recent releases

Popularity58

Moderate usage in the ecosystem

Community40

Growing community involvement

Maturity72

Established project with proven stability

 Bus Factor1

Top contributor holds 62.8% 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 ~11 days

Recently: every ~5 days

Total

93

Last Release

16d ago

Major Versions

v3.1.57 → v4.0.0-beta.12025-06-28

v3.1.58 → v4.0.0-beta.22025-07-22

v3.2.0 → 4.x-dev2026-06-18

PHP version history (2 changes)v3.0.0PHP ^8.1

v4.0.0-beta.1PHP ^8.2

### Community

Maintainers

![](https://www.gravatar.com/avatar/6d47a56dfab94e67a7354a146f96a0285c09f6b9d649c558832c6a9b94354b8c?d=identicon)[CodeWithDennis](/maintainers/CodeWithDennis)

---

Top Contributors

[![CodeWithDennis](https://avatars.githubusercontent.com/u/23448484?v=4)](https://github.com/CodeWithDennis "CodeWithDennis (301 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (32 commits)")[![gp-lnuff](https://avatars.githubusercontent.com/u/169065476?v=4)](https://github.com/gp-lnuff "gp-lnuff (24 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (24 commits)")[![lotestudio](https://avatars.githubusercontent.com/u/1052691?v=4)](https://github.com/lotestudio "lotestudio (21 commits)")[![buzkall](https://avatars.githubusercontent.com/u/5702?v=4)](https://github.com/buzkall "buzkall (10 commits)")[![saade](https://avatars.githubusercontent.com/u/14329460?v=4)](https://github.com/saade "saade (9 commits)")[![gpibarra](https://avatars.githubusercontent.com/u/21188012?v=4)](https://github.com/gpibarra "gpibarra (7 commits)")[![nathanheffley](https://avatars.githubusercontent.com/u/8952123?v=4)](https://github.com/nathanheffley "nathanheffley (6 commits)")[![markvaneijk](https://avatars.githubusercontent.com/u/1925388?v=4)](https://github.com/markvaneijk "markvaneijk (5 commits)")[![iotron](https://avatars.githubusercontent.com/u/50877415?v=4)](https://github.com/iotron "iotron (5 commits)")[![laravel-shift](https://avatars.githubusercontent.com/u/15991828?v=4)](https://github.com/laravel-shift "laravel-shift (4 commits)")[![A909M](https://avatars.githubusercontent.com/u/119125167?v=4)](https://github.com/A909M "A909M (3 commits)")[![ariaieboy](https://avatars.githubusercontent.com/u/15873972?v=4)](https://github.com/ariaieboy "ariaieboy (3 commits)")[![Casmo](https://avatars.githubusercontent.com/u/385764?v=4)](https://github.com/Casmo "Casmo (3 commits)")[![felixgilles](https://avatars.githubusercontent.com/u/900854?v=4)](https://github.com/felixgilles "felixgilles (3 commits)")[![mgkimsal](https://avatars.githubusercontent.com/u/75154?v=4)](https://github.com/mgkimsal "mgkimsal (3 commits)")[![stefket](https://avatars.githubusercontent.com/u/1169903?v=4)](https://github.com/stefket "stefket (3 commits)")[![Baspa](https://avatars.githubusercontent.com/u/10845460?v=4)](https://github.com/Baspa "Baspa (2 commits)")[![mohamedsabil83](https://avatars.githubusercontent.com/u/10126040?v=4)](https://github.com/mohamedsabil83 "mohamedsabil83 (2 commits)")

---

Tags

fieldfilamentfilament-pluginfilamentphplaravelphpselectselect-treetreetree-structurelaraveltreefilamentCodeWithDennisfilament-select-tree

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/codewithdennis-filament-select-tree/health.svg)

```
[![Health](https://phpackages.com/badges/codewithdennis-filament-select-tree/health.svg)](https://phpackages.com/packages/codewithdennis-filament-select-tree)
```

###  Alternatives

[spatie/laravel-pdf

Create PDFs in Laravel apps

1.0k4.8M47](/packages/spatie-laravel-pdf)[rawilk/profile-filament-plugin

Profile &amp; MFA starter kit for filament.

3914.6k](/packages/rawilk-profile-filament-plugin)[rawilk/filament-password-input

Enhanced password input component for filament.

52263.4k14](/packages/rawilk-filament-password-input)[stephenjude/filament-jetstream

A Laravel starter kit built with Filament inspired by Jetstream.

17760.2k3](/packages/stephenjude-filament-jetstream)[danihidayatx/image-optimizer

Optimize your Filament images before they reach your database. Forked from joshembling/image-optimizer for Filament v4 &amp; v5 support.

3218.1k](/packages/danihidayatx-image-optimizer)[awcodes/richer-editor

A collection of extensions and tools to enhance the Filament Rich Editor field.

3912.9k9](/packages/awcodes-richer-editor)

PHPackages © 2026

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