Kanban
A collection of cards arranged in columns, representing different stages of a workflow.
Basic Usage
A simple kanban board with columns and cards:
<neura::kanban :columns="[
[
'title' => 'To Do',
'cards' => [
[
'title' => 'Design new homepage',
'subtitle' => 'Task #123',
'description' => 'Create wireframes and mockups',
],
],
],
[
'title' => 'In Progress',
'cards' => [
[
'title' => 'Implement authentication',
'badge' => 'High',
],
],
],
[
'title' => 'Done',
'cards' => [
[
'title' => 'Setup project structure',
],
],
],
]" />
With Column Descriptions
Add descriptions to columns to provide more context:
<neura::kanban :columns="[
[
'title' => 'Backlog',
'description' => 'Items waiting to be prioritized',
'cards' => [...],
],
[
'title' => 'Sprint Planning',
'description' => 'Items being planned for next sprint',
'cards' => [...],
],
]" />
Cards with Metadata
Add metadata tags to cards for additional information:
<neura::kanban :columns="[
[
'title' => 'Development',
'cards' => [
[
'title' => 'Build dashboard',
'subtitle' => 'Feature #456',
'description' => 'Create admin dashboard',
'meta' => ['Frontend', 'React', 'Priority'],
'badge' => 'Urgent',
],
],
],
]" />
Cards with Footer
Add footer information to cards:
<neura::kanban :columns="[
[
'title' => 'Review',
'cards' => [
[
'title' => 'Code review',
'subtitle' => 'PR #789',
'description' => 'Review authentication',
'footer' => 'Assigned to: John Doe · Due: Dec 15',
],
],
],
]" />
Column Actions
Add action buttons to columns:
<neura::kanban :columns="[
[
'title' => 'To Do',
'cards' => [...],
'action' => [
'label' => 'Add Card',
'icon' => 'plus',
'attributes' => [
'wire:click' => 'addCard',
],
],
],
]" />
Empty States
Customize empty state messages for columns and the entire board:
<neura::kanban
:columns="[
[
'title' => 'Empty Column',
'cards' => [],
'emptyState' => 'No tasks in this column',
],
]"
emptyState="No columns available"
/>
Complete Example
A complete kanban board example with all features:
Properties
| Property | Type | Default | Description |
|---|---|---|---|
| columns | array | [] | Array of column objects with title, cards, and optional properties |
| emptyState | string|null | null | Custom message when board has no columns |
| onCardClick | string|null | null | Livewire method name to call when a card is clicked. Receives (card, columnIndex, cardIndex). Ignored when card was just dragged. |
Column Structure
Each column in the columns array can have the following properties:
| Property | Type | Required | Description |
|---|---|---|---|
| title | string | Yes | Column header title |
| description | string | No | Optional description below the title |
| cards | array | No | Array of card objects |
| emptyState | string | No | Custom message when column has no cards |
| action | array | No | Action button configuration (label, icon, attributes) |
| class | string | No | Additional CSS classes for the column |
Card Structure
Each card in the cards array can have the following properties:
| Property | Type | Required | Description |
|---|---|---|---|
| title | string | No | Card main title |
| subtitle | string | No | Secondary text below the title |
| description | string | No | Detailed description of the card |
| badge | string | No | Badge text displayed in the top right |
| meta | array|string | No | Array of metadata tags or single string |
| footer | string | No | Footer text displayed at the bottom of the card |
Using with Livewire
The Kanban component fully supports Livewire for server-side state management. Use
wire:model to bind the columns array to a Livewire property.
Basic Livewire Integration
Create a Livewire component with a columns property:
<?php
namespace App\View\Pages\Backend\Tasks;
use Livewire\Component;
class KanbanBoard extends Component
{
public $columns = [];
public function mount()
{
$this->columns = [
[
'title' => 'To Do',
'cards' => [
[
'title' => 'Task 1',
'description' => 'First task',
],
],
],
[
'title' => 'In Progress',
'cards' => [],
],
[
'title' => 'Done',
'cards' => [],
],
];
}
public function render()
{
return view('pages.backend.tasks.kanban-board');
}
}
Then use the component in your Blade view:
<div>
<neura::kanban
wire:model="columns"
:draggable="true"
:draggableColumns="true"
onCardClick="openCard"
/>
</div>
Card Click Handler
Use
onCardClick to call a Livewire method when a card is clicked. The method receives the card object, column index, and card index. Clicks after a drag are ignored.
public function openCard($card, $columnIndex, $cardIndex)
{
// Open modal, navigate, etc.
$this->selectedCard = $card;
}
Example: Open Sideover on Card Click
Click a card to open its details in a sideover:
<neura::kanban
wire:model="kanbanColumns"
onCardClick="openCard"
:draggable="true"
/>
// In your Livewire component:
public function openCard(array $card, int $columnIndex, int $cardIndex): void
{
$this->sideover(KanbanCardSideover::class)
->with('card', $card)
->with('columnIndex', $columnIndex)
->with('cardIndex', $cardIndex)
->width('md')
->open();
}
Handling Card Moves
Listen to card move events to perform server-side actions:
<?php
namespace App\View\Pages\Backend\Tasks;
use Livewire\Component;
class KanbanBoard extends Component
{
public $columns = [];
protected $listeners = ['kanban:card-moved' => 'handleCardMove'];
public function handleCardMove($event)
{
$card = $event['card'];
$fromColumn = $event['fromColumn'];
$toColumn = $event['toColumn'];
// Update database, send notifications, etc.
// The columns array is already updated via wire:model
}
public function render()
{
return view('pages.backend.tasks.kanban-board');
}
}
Using wire:model.live
For real-time updates, use
wire:model.live:
<neura::kanban
wire:model.live="columns"
:draggable="true"
/>
Complete Example
A complete example with database persistence:
<?php
namespace App\View\Pages\Backend\Tasks;
use App\Models\Task;
use Livewire\Component;
class KanbanBoard extends Component
{
public $columns = [];
public function mount()
{
$this->loadColumns();
}
protected $listeners = ['kanban:card-moved' => 'onCardMoved'];
public function loadColumns()
{
$tasks = Task::all();
$this->columns = [
[
'title' => 'To Do',
'cards' => $tasks->where('status', 'todo')
->map(fn($task) => [
'id' => $task->id,
'title' => $task->title,
'description' => $task->description,
])->toArray(),
],
[
'title' => 'In Progress',
'cards' => $tasks->where('status', 'in_progress')
->map(fn($task) => [
'id' => $task->id,
'title' => $task->title,
'description' => $task->description,
])->toArray(),
],
[
'title' => 'Done',
'cards' => $tasks->where('status', 'done')
->map(fn($task) => [
'id' => $task->id,
'title' => $task->title,
'description' => $task->description,
])->toArray(),
],
];
}
public function onCardMoved($event)
{
$card = $event['card'];
$toColumn = $event['toColumn'];
$statusMap = ['todo', 'in_progress', 'done'];
$status = $statusMap[$toColumn] ?? 'todo';
Task::find($card['id'])->update(['status' => $status]);
$this->dispatch('notify', [
'type' => 'success',
'content' => 'Task moved successfully',
]);
}
public function render()
{
return view('pages.backend.tasks.kanban-board');
}
}
<!-- resources/views/pages/backend/tasks/kanban-board.blade.php -->
<div>
<neura::kanban
wire:model="columns"
:draggable="true"
:showCount="true"
/>
</div>
Best Practices
✓ Do
- Use clear column titles that indicate the stage or status of items
- Keep cards concise with essential information
- Use metadata for categorization (tags, priorities, types)
- Provide meaningful empty states with guidance
- Use column actions for common tasks (add item, etc.)
✗ Don't
- Use too many columns — keep it to 5–7 for clarity
- Overcrowd columns with too many cards
- Use vague or generic column titles like "Other"
- Show too much information on each card
- Forget to handle empty or loading states