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.
You can install the package via composer:
composer require codewithdennis/filament-select-tree
php artisan filament:assets
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')
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));
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()
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)
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)
By default, the tree key (wire key) will be a random generated value, you can change this 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) { $categories = [(int) $data['category']]; return $query->when($data['category'], function (Builder $query, $categories) { if($data['category'] === -1){ return $query->whereDoesntHave('categories'); } return $query->whereHas('categories', fn(Builder $query) => $query->whereIn('id', $categories)); }); })])
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()); })])
Please see CONTRIBUTING for details.
Please review our security policy on how to report security vulnerabilities.
The MIT License (MIT). Please see License File for more information.