PHPackages                             saade/filament-adjacency-list - 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. saade/filament-adjacency-list

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

saade/filament-adjacency-list
=============================

A Filament package to adjacency lists.

v4.1.1(1mo ago)9873.8k↑25.5%25[1 issues](https://github.com/saade/filament-adjacency-list/issues)7MITPHPPHP ^8.2CI passing

Since Aug 17Pushed 2w ago5 watchersCompare

[ Source](https://github.com/saade/filament-adjacency-list)[ Packagist](https://packagist.org/packages/saade/filament-adjacency-list)[ Docs](https://github.com/saade/filament-adjacency-list)[ GitHub Sponsors](https://github.com/saade)[ RSS](/packages/saade-filament-adjacency-list/feed)WikiDiscussions 4.x Synced 2w ago

READMEChangelog (10)Dependencies (77)Versions (31)Used By (7)

Filament Adjacency List
=======================

[](#filament-adjacency-list)

[![Latest Version on Packagist](https://camo.githubusercontent.com/1c100441a87ad3c5ffa619686e60a4e0fcfa2fa47c7991b7923c6f310f385121/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f73616164652f66696c616d656e742d61646a6163656e63792d6c6973742e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/saade/filament-adjacency-list)[![Total Downloads](https://camo.githubusercontent.com/2ea0dfe062de60db4a100580062b87eef082df99a3d32dd5adb5f54ebdc90716/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f73616164652f66696c616d656e742d61646a6163656e63792d6c6973742e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/saade/filament-adjacency-list)

A Filament package to manage adjacency lists (aka trees).

 [![Banner](https://raw.githubusercontent.com/saade/filament-adjacency-list/3.x/art/cover.png)](https://raw.githubusercontent.com/saade/filament-adjacency-list/3.x/art/cover.png)

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

[](#installation)

You can install the package via composer:

```
composer require saade/filament-adjacency-list
```

Important

If you have not set up a custom theme and are using Filament Panels follow the instructions in the [Filament Docs](https://filamentphp.com/docs/4.x/styling/overview#creating-a-custom-theme) first.

After setting up a custom theme add the plugin's views to your theme css file or your app's css file if using the standalone packages.

```
@source '../../../../vendor/saade/filament-adjacency-list/resources/views/**/*.blade.php';
```

Usage
-----

[](#usage)

```
use Saade\FilamentAdjacencyList\Forms\Components\AdjacencyList;

AdjacencyList::make('subjects')
    ->form([
        Forms\Components\TextInput::make('label')
            ->required(),
    ])
```

Configuration
-------------

[](#configuration)

### Customizing the `label` key used to display the item's label

[](#customizing-the-label-key-used-to-display-the-items-label)

```
AdjacencyList::make('subjects')
    ->labelKey('name')          // defaults to 'label'
```

### Customizing the `children` key used to gather the item's children.

[](#customizing-the-children-key-used-to-gather-the-items-children)

> **Note:** This is only used when not using relationships.

```
AdjacencyList::make('subjects')
    ->childrenKey('children')   // defaults to 'children'
```

### Customizing the `MaxDepth` of the tree.

[](#customizing-the-maxdepth-of-the-tree)

```
AdjacencyList::make('subjects')
    ->maxDepth(2)               // defaults to -1 (unlimited depth)
```

### Triggering an action or opening a URL when clicking on an item.

[](#triggering-an-action-or-opening-a-url-when-clicking-on-an-item)

```
AdjacencyList::make('subjects')
    ->itemAction('edit') // or view, delete, moveUp, indent etc ...
    ->itemUrl(
        fn (array $item) => YourResource::getUrl('view', ['record' => $item['id']]) // for example
    )
```

### Customizing the item label using a closure.

[](#customizing-the-item-label-using-a-closure)

```
AdjacencyList::make('subjects')
    ->itemLabel(
        fn (array $item): ?string => Page::find($item['data']['id'], ['name'])?->name)
    )
```

### Creating items without a modal.

[](#creating-items-without-a-modal)

```
AdjacencyList::make('subjects')
    ->modal(false)      // defaults to true
```

### Disabling creation, edition, deletion, reordering, moving, and indenting.

[](#disabling-creation-edition-deletion-reordering-moving-and-indenting)

```
AdjacencyList::make('subjects')
    ->addable(false)
    ->editable(false)
    ->deletable(false)
    ->reorderable(false)
    ->moveable(false)
    ->indentable(false)
```

### Customizing actions

[](#customizing-actions)

```
use Filament\Forms\Actions\Action;

AdjacencyList::make('subjects')
    ->addAction(fn (Action $action): Action => $action->icon('heroicon-o-plus')->color('primary'))
    ->addChildAction(fn (Action $action): Action => $action->button())
    ->editAction(fn (Action $action): Action => $action->icon('heroicon-o-pencil'))
    ->deleteAction(fn (Action $action): Action => $action->requiresConfirmation())
    ->reorderAction(fn (Action $action): Action => $action->icon('heroicon-o-arrow-path-rounded-square'))
```

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

[](#relationships)

In this example, we'll be creating a Ticketing system, where tickets can be assigned to a department, and departments have subjects.

### Building the relationship

[](#building-the-relationship)

```
// App/Models/Department.php

class Department extends Model
{
    public function subjects(): HasMany
    {
        return $this->hasMany(Subject::class)->whereNull('parent_id')->with('children')->orderBy('sort');
    }
}
```

```
// App/Models/Subject.php

class Subject extends Model
{
    protected $fillable ['parent_id', 'name', 'sort']; // or whatever your columns are

    public function children(): HasMany
    {
        return $this->hasMany(Subject::class, 'parent_id')->with('children')->orderBy('sort');
    }
}
```

Now you've created a nested relationship between departments and subjects.

### Using the relationship

[](#using-the-relationship)

```
// App/Filament/Resources/DepartmentResource.php

AdjacencyList::make('subjects')
    ->relationship('subjects')          // Define the relationship
    ->labelKey('name')                  // Customize the label key to your model's column
    ->childrenKey('children')           // Customize the children key to the relationship's method name
    ->form([                            // Define the form
        Forms\Components\TextInput::make('name')
            ->label(__('Name'))
            ->required(),
    ]);
```

That's it! Now you're able to manage your adjacency lists using relationships.

### Working with Staudenmeir's Laravel Adjacency List

[](#working-with-staudenmeirs-laravel-adjacency-list)

This package also supports [Staudenmeir's Laravel Adjacency List](https://github.com/staudenmeir/laravel-adjacency-list) package.

First, install the package:

```
composer require staudenmeir/laravel-adjacency-list:"^1.0"
```

1. Use the `HasRecursiveRelationships` trait in your model, and override the default path separator.

```
// App/Models/Department.php

class Department extends Model
{
    use \Staudenmeir\LaravelAdjacencyList\Eloquent\HasRecursiveRelationships;

    public function getPathSeparator()
    {
        return '.children.';
    }
}
```

If you're already using the HasRecursiveRelationships trait for other parts of your application, it's probably not a good idea to change your model's path separator, since it can break other parts of your application. Instead, you can add as many path separators as you want:

```
class Department extends Model
{
    use \Staudenmeir\LaravelAdjacencyList\Eloquent\HasRecursiveRelationships;

    public function getCustomPaths()
    {
        return [
            [
                'name' => 'tree_path',
                'column' => 'id',
                'separator' => '.children.',
            ],
        ];
    }
}
```

2. Use the `relationship` method to define the relationship:

```
AdjacencyList::make('subdepartments')
    ->relationship('descendants')   // or 'descendantsAndSelf', 'children' ...
    ->customPath('tree_path')       // if you're using custom paths
```

That's it! Now you're able to manage your adjacency lists using relationships.

### Customizing the query

[](#customizing-the-query)

```
AdjacencyList::make('subdepartments')
    ->relationship('descendants', fn (Builder $query): Builder => $query->where('enabled', 1))
```

### Ordering

[](#ordering)

If your application needs to order the items in the list, you can use the `orderColumn` method:

```
AdjacencyList::make('subdepartments')
    ->orderColumn('sort')   // or any other column
```

Widget
------

[](#widget)

The `AdjacencyListWidget` can be used to render a tree for any model with a recursive child relationship (including many-to-many graph relationships, using Staudenmeir's HasGraphRelationships trait).

The simplest use case is ...

```
class DepartmentTreeWidget extends AdjacencyListWidget
{
    protected static string $relationshipName = 'descendantsAndSelf';

    // If you're using a widget on an Edit or View page, the plugin will automatically set the $record for you.
    // However, you're free to override this method to customize the record.
    public function getModel(): Model | string | null
    {
        return Department::query()->where(['is_root' => true])->first();
    }

    // You can configure the widget using the same methods as the form component.
    protected function adjacencyList(AdjacencyList $adjacencyList): AdjacencyList
    {
        return $adjacencyList
            ->label('Foo')
            ->editable()
            ->labelKey('nombre')
            ->childrenKey('hijos');
    }
}
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

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)

- [Saade](https://github.com/saade)
- [Ryan Chandler's Navigation Plugin](https://github.com/ryangjchandler/filament-navigation) for his work on the tree UI and complex tree actions.
- [Hugh](https://github.com/cheesegrits) for his help on supporting trees/ graphs relationships.
- [All Contributors](../../contributors)

License
-------

[](#license)

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

 [ ![Sponsor Saade](https://raw.githubusercontent.com/saade/filament-adjacency-list/3.x/art/sponsor.png) ](https://github.com/sponsors/saade)

###  Health Score

63

—

FairBetter than 99% of packages

Maintenance94

Actively maintained with recent releases

Popularity48

Moderate usage in the ecosystem

Community32

Small or concentrated contributor base

Maturity68

Established project with proven stability

 Bus Factor2

2 contributors hold 50%+ of commits

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 ~46 days

Recently: every ~21 days

Total

24

Last Release

20d ago

Major Versions

v3.2.1 → v4.0.0-beta12024-08-26

v3.2.2 → v4.0.0-beta32025-02-26

v3.3.0 → v4.0.12026-02-18

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

v4.0.2PHP ^8.2

### Community

Maintainers

![](https://www.gravatar.com/avatar/a71deedec445b71a667043e26cdf835628920543cc54e4fba0d1cc592958e5a0?d=identicon)[saade](/maintainers/saade)

---

Top Contributors

[![saade](https://avatars.githubusercontent.com/u/14329460?v=4)](https://github.com/saade "saade (107 commits)")[![cheesegrits](https://avatars.githubusercontent.com/u/934456?v=4)](https://github.com/cheesegrits "cheesegrits (42 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (28 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (17 commits)")[![vanhooff](https://avatars.githubusercontent.com/u/51762658?v=4)](https://github.com/vanhooff "vanhooff (12 commits)")[![CodeWithDennis](https://avatars.githubusercontent.com/u/23448484?v=4)](https://github.com/CodeWithDennis "CodeWithDennis (5 commits)")[![atmonshi](https://avatars.githubusercontent.com/u/1952412?v=4)](https://github.com/atmonshi "atmonshi (2 commits)")[![danharrin](https://avatars.githubusercontent.com/u/41773797?v=4)](https://github.com/danharrin "danharrin (2 commits)")[![howdu](https://avatars.githubusercontent.com/u/533658?v=4)](https://github.com/howdu "howdu (2 commits)")[![iotron](https://avatars.githubusercontent.com/u/50877415?v=4)](https://github.com/iotron "iotron (2 commits)")[![markvaneijk](https://avatars.githubusercontent.com/u/1925388?v=4)](https://github.com/markvaneijk "markvaneijk (1 commits)")[![RibesAlexandre](https://avatars.githubusercontent.com/u/818564?v=4)](https://github.com/RibesAlexandre "RibesAlexandre (1 commits)")[![htulibacki](https://avatars.githubusercontent.com/u/969692?v=4)](https://github.com/htulibacki "htulibacki (1 commits)")[![sadegh19b](https://avatars.githubusercontent.com/u/54643531?v=4)](https://github.com/sadegh19b "sadegh19b (1 commits)")[![tlegenbayangali](https://avatars.githubusercontent.com/u/39906549?v=4)](https://github.com/tlegenbayangali "tlegenbayangali (1 commits)")[![GhostvOne](https://avatars.githubusercontent.com/u/798011?v=4)](https://github.com/GhostvOne "GhostvOne (1 commits)")

---

Tags

adjacency-listfilamentform-builderlaraveltreelaravelsaadefilament-adjacency-list

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/saade-filament-adjacency-list/health.svg)

```
[![Health](https://phpackages.com/badges/saade-filament-adjacency-list/health.svg)](https://phpackages.com/packages/saade-filament-adjacency-list)
```

###  Alternatives

[rawilk/profile-filament-plugin

Profile &amp; MFA starter kit for filament.

3915.5k](/packages/rawilk-profile-filament-plugin)[backstage/mails

View logged mails and events in a beautiful Filament UI.

16429.7k](/packages/backstage-mails)[finity-labs/fin-mail

A powerful email template manager and composer for Filament with dynamic token replacement, template versioning, and inline email sending.

316.8k2](/packages/finity-labs-fin-mail)[stephenjude/filament-jetstream

A Laravel starter kit built with Filament inspired by Jetstream.

17861.9k3](/packages/stephenjude-filament-jetstream)[stephenjude/filament-debugger

About

104173.6k2](/packages/stephenjude-filament-debugger)[tapp/filament-form-builder

User facing form builder using Filament components

133.5k6](/packages/tapp-filament-form-builder)

PHPackages © 2026

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