alessandro-nuunes/filament-kanban

Kanban board pages for Filament v5 panels.

Maintainers

Package info

github.com/alessandronuunes/filament-kanban

Homepage

Issues

pkg:composer/alessandro-nuunes/filament-kanban

Fund package maintenance!

alessandro-nuunes

Statistics

Installs: 8

Dependents: 0

Suggesters: 0

Stars: 0

v1.0.0 2026-03-28 12:33 UTC

This package is auto-updated.

Last update: 2026-03-28 12:39:50 UTC


README

Kanban board pages for Filament v5 panels (PHP 8.2+ / Laravel 11–12).

First Kanban plugin built natively for Filament v5.
Drag-and-drop, status transitions, edit modal, Enum integration, dark mode.

Requirements

  • PHP 8.2+
  • Laravel 11.x or 12.x
  • Filament 5.x

Installation

composer require alessandro-nuunes/filament-kanban

Publish config and translations:

php artisan filament-kanban:install

Add the @source to your Filament theme CSS so Tailwind picks up the plugin classes:

/* resources/css/filament/admin/theme.css */

/* via Composer (production) */
@source '../../../../vendor/alessandro-nuunes/filament-kanban/resources/views/**/*';

/* via local packages/ (development) */
@source '../../../../packages/filament-kanban/resources/views/**/*';

Then rebuild assets:

npm run build

Quick Start

1. Generate a Kanban page

php artisan make:filament-kanban TicketsKanban --resource=TaskResource --model=Task --panel=admin

This creates app/Filament/Admin/Resources/Tasks/Pages/TicketsKanban.php.

2. Register it in your Resource

// TaskResource.php
public static function getPages(): array
{
    return [
        'index'  => Pages\ListTasks::route('/'),
        'kanban' => Pages\TicketsKanban::route('/kanban'),
        'view'   => Pages\ViewTask::route('/{record}'),
    ];
}

3. Add your Enum (optional but recommended)

use AlessandroNuunes\FilamentKanban\Contracts\HasKanbanStatuses;
use AlessandroNuunes\FilamentKanban\Concerns\InteractsWithKanbanStatuses;
use Filament\Support\Contracts\HasColor;
use Filament\Support\Contracts\HasLabel;

enum TaskStatus: string implements HasKanbanStatuses, HasColor, HasLabel
{
    use InteractsWithKanbanStatuses;

    case Pending    = 'pending';
    case InProgress = 'in_progress';
    case Completed  = 'completed';
    case Cancelled  = 'cancelled';

    // Only show these 3 on the board
    public static function kanbanCases(): array
    {
        return [self::Pending, self::InProgress, self::Completed];
    }

    public function getLabel(): ?string
    {
        return match ($this) {
            self::Pending    => 'Pending',
            self::InProgress => 'In Progress',
            self::Completed  => 'Completed',
            self::Cancelled  => 'Cancelled',
        };
    }

    public function getColor(): string|array|null
    {
        return match ($this) {
            self::Pending    => 'warning',
            self::InProgress => 'info',
            self::Completed  => 'success',
            self::Cancelled  => 'gray',
        };
    }
}

4. Point the board to your Enum

class TicketsKanban extends KanbanBoard
{
    protected static string $resource             = TaskResource::class;
    protected static string $model                = Task::class;
    protected static ?string $statusEnum          = TaskStatus::class;
    protected static string $recordStatusAttribute = 'status';
    protected static string $recordTitleAttribute  = 'protocol';

    protected function onStatusChanged(
        int|string $recordId,
        string $newStatus,
        array $fromOrderedIds,
        array $toOrderedIds,
    ): void {
        Task::find($recordId)?->update(['status' => $newStatus]);
    }
}

Configuration

config/filament-kanban.php

return [
    // 'record' = calls canMoveRecord() on the page
    // 'policy' = calls $policy->update($user, $record)
    'authorization_mode' => 'record',

    'default_status_attribute' => 'status',
    'default_title_attribute'  => 'title',

    // Max height of each column's scroll area
    'board_max_height' => '75vh',

    // Enable the inline edit modal (click on card)
    'enable_edit_modal' => true,
];

All overridable methods

Method Description
statuses(): Collection Manual statuses when not using an Enum
records(): Collection Filter/scope which records appear
onStatusChanged(...) Persist status change + side-effects
onSortChanged(...) Persist reordering within a column
canMoveRecord(Model, from, to): bool Block specific moves
allowedTransitions(): ?array Restrict status-to-status transitions
mutateRecordDataForCard(array, Model) Customize data passed to card view
getEditModalFormSchema(?id): array Define edit modal form fields
editRecord(id, data, state): void Handle edit modal save
getSortColumn(): ?string Column name for persistent ordering
shouldPersistSorting(): bool Whether to persist column sort order

Status transitions

protected function allowedTransitions(): ?array
{
    return [
        'pending'     => ['in_progress', 'cancelled'],
        'in_progress' => ['completed', 'pending'],
        // null or missing key = no restriction from that status
    ];
}

Manual statuses (no Enum)

protected function statuses(): Collection
{
    return collect([
        ['id' => 'todo',        'title' => 'To Do',       'color' => 'gray'],
        ['id' => 'in_progress', 'title' => 'In Progress',  'color' => 'info'],
        ['id' => 'done',        'title' => 'Done',         'color' => 'success'],
    ]);
}

Events

Listen to these events in your application:

use AlessandroNuunes\FilamentKanban\Events\KanbanRecordStatusChanging;
use AlessandroNuunes\FilamentKanban\Events\KanbanRecordStatusChanged;
use AlessandroNuunes\FilamentKanban\Events\KanbanRecordSortingChanged;

Event::listen(KanbanRecordStatusChanged::class, function ($event) {
    // $event->userId, recordId, fromStatus, toStatus, fromOrderedIds, toOrderedIds
});

Customizing views

Publish all views:

php artisan vendor:publish --tag="filament-kanban-views"

Or override per board:

protected static string $boardView   = 'my-package::kanban-board';
protected static string $columnView  = 'my-package::kanban-column';
protected static string $cardView    = 'my-package::kanban-card';
protected static string $emptyView   = 'my-package::kanban-empty';
protected static string $scriptsView = 'my-package::kanban-scripts';

Theme (required)

/* production */
@source '../../../../vendor/alessandro-nuunes/filament-kanban/resources/views/**/*';

/* local development */
@source '../../../../packages/filament-kanban/resources/views/**/*';

License

MIT — see LICENSE.md.

Author

Alessandro NuunesGitHub