Kanban
Arguably the most complex component in Aura, the Kanban component provides a robust way to render and manage a kanban board. It includes both frontend and backend components that work together seamlessly. The frontend handles the interactive UI using Muuri.js for drag-and-drop functionality, while the backend component integrates with Livewire to manage data persistence and event handling.
Attributes
static
- (bool) When set, columns become static and cannot be dragged (items within columns remain draggable).
Basic Usage
<aura:board>
<aura:board.column>
<aura:board.column.header>
To Do
</aura:board.column.header>
<aura:board.column.content>
<aura:board.card>
Drink a cup of coffee
</aura:board.card>
<aura:board.card>
Make another cup of coffee
</aura:board.card>
</aura:board.column.content>
</aura:board.column>
<aura:board.column>
<aura:board.column.header>
Done
</aura:board.column.header>
<aura:board.column.content>
<aura:board.card>
Make a cup of coffee
</aura:board.card>
</aura:board.column.content>
</aura:board.column>
</aura:board>
Static Columns
When the static
attribute is set, the columns become static and cannot be dragged. However, items within the columns
remain draggable.
<aura:board static>
<!-- ... -->
</aura:board>
Caveats
The root element requires some specific CSS considerations. It needs a parent with explicitly defined dimensions ( non-computed height and width) to render correctly:
<div class="w-[1080px] h-96">
<aura:board>
...
</aura:board>
</div>
For filling the aura:main
component, use this workaround:
<div class="h-full w-full">
<div class="h-full w-full min-h-96 flex relative">
<div class="absolute inset-0">
<aura:board>
...
</aura:board>
</div>
</div>
</div>
Backend
The backend is powered by an abstract Livewire component, BoardComponent
, which serves as the bridge between the
frontend kanban board and your application's data storage. It handles all events dispatched from the frontend and
provides methods to persist changes.
Implementation
To use the Kanban component, you must extend BoardComponent
and implement its abstract methods. Here's a complete
example:
namespace App\Http\Livewire;
use App\Models\KanbanColumn;
use App\Models\KanbanItem;
use Livewire\Component;
use Aura\Livewire\BoardComponent;
class KanbanBoard extends BoardComponent
{
public $columns = [];
public function mount()
{
// Load initial data
$this->columns = KanbanColumn::with('items')->get()->toArray();
}
protected function updateItemPosition(string $itemId, string $toColumnId, int &$toIndex): void
{
$item = KanbanItem::findOrFail($itemId);
$item->column_id = $toColumnId;
$item->position = $toIndex;
$item->save();
// Reorder other items in the column if needed
KanbanItem::where('column_id', $toColumnId)
->where('id', '!=', $itemId)
->orderBy('position')
->get()
->each(function ($item, $index) use ($toIndex) {
$item->position = ($index >= $toIndex) ? $index + 1 : $index;
$item->save();
});
}
protected function updateColumnPosition(string $columnId, int &$toIndex): void
{
$column = KanbanColumn::findOrFail($columnId);
$column->position = $toIndex;
$column->save();
// Reorder other columns
KanbanColumn::where('id', '!=', $columnId)
->orderBy('position')
->get()
->each(function ($column, $index) use ($toIndex) {
$column->position = ($index >= $toIndex) ? $index + 1 : $index;
$column->save();
});
}
protected function createItem(string $columnId, int &$index, array $itemData): string
{
$item = KanbanItem::create([
'column_id' => $columnId,
'title' => $itemData['title'] ?? 'New Item',
'position' => $index,
]);
return "<div data-aura-board-item data-aura-board-item-id='{$item->id}'>{$item->title}</div>";
}
protected function createColumn(int &$index, array $columnData): string
{
$column = KanbanColumn::create([
'title' => $columnData['title'] ?? 'New Column',
'position' => $index,
]);
return "
<div data-aura-board-column data-aura-board-column-id='{$column->id}'>
<div data-aura-board-column-header>{$column->title}</div>
<div data-aura-board-column-content></div>
</div>
";
}
protected function removeItem(string $itemId): void
{
KanbanItem::findOrFail($itemId)->delete();
}
protected function removeColumn(string $columnId): void
{
$column = KanbanColumn::findOrFail($columnId);
$column->items()->delete(); // Delete associated items
$column->delete();
}
// Optional: Render method if you're using a custom view
public function render()
{
return view('livewire.kanban-board', [
'columns' => $this->columns,
]);
}
}
Required Methods
The BoardComponent
abstract class requires you to implement these methods:
-
updateItemPosition(string $itemId, string $toColumnId, int &$toIndex): void
- Updates an item's position when dragged to a new column or position.
- Parameters: Item ID, target column ID, and target index (passed by reference).
-
updateColumnPosition(string $columnId, int &$toIndex): void
- Updates a column's position when reordered.
- Parameters: Column ID and target index (passed by reference).
-
createItem(string $columnId, int &$index, array $itemData): string
- Creates a new item and returns its HTML representation.
- Parameters: Target column ID, index, and item data array.
- Must return HTML matching the
data-aura-board-item
structure.
-
createColumn(int &$index, array $columnData): string
- Creates a new column and returns its HTML representation.
- Parameters: Index and column data array.
- Must return HTML matching the
data-aura-board-column
structure.
-
removeItem(string $itemId): void
- Removes an item from the backend storage.
- Parameter: Item ID.
-
removeColumn(string $columnId): void
- Removes a column and optionally its items from the backend.
- Parameter: Column ID.
Events
The backend listens for and dispatches these Livewire events:
moved-board-item
→ CallsupdateItemPosition
moved-column
→ CallsupdateColumnPosition
add-board-item
→ CallscreateItem
add-column
→ CallscreateColumn
delete-board-item
→ CallsremoveItem
delete-column
→ CallsremoveColumn
Database Schema Example
Schema::create('kanban_columns', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->integer('position')->default(0);
$table->timestamps();
});
Schema::create('kanban_items', function (Blueprint $table) {
$table->id();
$table->foreignId('column_id')->constrained('kanban_columns')->cascadeOnDelete();
$table->string('title');
$table->integer('position')->default(0);
$table->timestamps();
});
Frontend Integration
The frontend dispatches events to Livewire, which are handled by these methods. Ensure your frontend HTML includes
proper data-aura-*
attributes matching your backend IDs.
This updated documentation provides a comprehensive guide to both frontend usage and backend implementation, including a practical example and database considerations. Let me know if you'd like to expand any section further!
© 2025 kolleg-essig. All rights reserved.