Kanban
KanbanTablero de columnas con tarjetas arrastrables, dentro y entre columnas: pipelines de CRM, gestión de tareas, flujos de aprobación. El arrastre usa x-sort, el plugin de Alpine que Livewire 4 trae embebido, sin dependencias nuevas.
Requiere Livewire. El arrastre llama a $wire.moveCard(...) en cada drop, así que la vista necesita un componente Livewire con el método handler —no funciona en un contexto Alpine puro sin Livewire cargado—.
Dos formas de usarlo
Igual que el DataTable: una clase base con estado, o un componente anónimo data-driven.
Esta página documenta el componente anónimo kore::kanban: el board no guarda estado propio, tú le pasas columnas y tarjetas y le dices qué método llamar en cada drop. Es la opción flexible: el board puede vivir dentro de otro componente Livewire (un dashboard, un modal), no necesita ser toda la página.
Si prefieres extender una clase y que la librería resuelva el render() por ti —el mismo patrón que KoreDataTable—, ve a KoreKanban, la clase base.
En vivo
Arrastra las tarjetas dentro de una columna para reordenarlas, o entre columnas para moverlas. Es un componente Livewire real: seis tareas en memoria, sin base de datos detrás.
Investigar competidores
Analizar 3 productos del mercado
Definir métricas
KPIs del trimestre
Diseñar el esquema de datos
Wireframes del panel
Migrar autenticación
A Livewire 4
Configurar CI
<x-kore::kanban
handler="moveCard"
:columns="$this->columns()"
:cards="$tasks"
/><x-kore::kanban
handler="moveCard"
:columns="$this->columns()"
:cards="$tasks"
/>public array $tasks = [
['id' => 1, 'column' => 'backlog', 'title' => 'Investigar competidores'],
['id' => 2, 'column' => 'todo', 'title' => 'Diseñar el esquema de datos'],
// ...
];
public function moveCard($cardId, $position, $toColumn): void
{
// $cardId = tarjeta movida · $position = índice destino dentro de $toColumn
// $toColumn = columna destino (se conoce al renderizar)
Task::whereKey($cardId)->update(['status' => $toColumn, 'position' => $position]);
}public array $tasks = [
['id' => 1, 'column' => 'backlog', 'title' => 'Investigar competidores'],
['id' => 2, 'column' => 'todo', 'title' => 'Diseñar el esquema de datos'],
// ...
];
public function moveCard($cardId, $position, $toColumn): void
{
// $cardId = tarjeta movida · $position = índice destino dentro de $toColumn
// $toColumn = columna destino (se conoce al renderizar)
Task::whereKey($cardId)->update(['status' => $toColumn, 'position' => $position]);
}Cómo funciona
El board no tiene estado: solo pinta lo que le pasas y delega el drop en tu handler.
- columns es la lista de cabeceras: cada una con
id,labely uncolorsemántico opcional para el punto de la cabecera. - cards es la lista plana de tarjetas: cada una lleva
column(el id de la columna a la que pertenece hoy), y el board las agrupa por columna al renderizar. Acepta array o Collection. - group es el grupo compartido de
x-sortentre columnas: por eso una tarjeta se puede soltar en otra columna y no solo reordenarse dentro de la suya. Por defecto usaconfig('kore-ui.kanban.group'), así que dos boards en la misma página no se mezclan mientras no compartan grupo a propósito. - animation son los milisegundos de la animación de arrastre (default 150).
Los colores de columna aceptan los tokens semánticos habituales: primary, success, warning, destructive, info, secondary.
La tarjeta
Por defecto pinta title, description y un badge opcional. Con el slot, el contenido es tuyo.
Cada tarjeta se renderiza con kore::kanban.card. Sin slot, muestra title, description (si existe) y un badge con su badgeColor (si existe) —así son las seis tarjetas de la demo de arriba—. Para contenido totalmente personalizado, pásale el slot: el card conserva el wire:key y el hook de arrastre, solo cambia lo que se pinta dentro.
<x-kore::kanban.card :card="$card">
<div class="flex items-center gap-2">
<x-kore::avatar :name="$card['assignee']" size="sm" />
<span class="text-sm">{{ $card['title'] }}</span>
</div>
</x-kore::kanban.card><x-kore::kanban.card :card="$card">
<div class="flex items-center gap-2">
<x-kore::avatar :name="$card['assignee']" size="sm" />
<span class="text-sm">{{ $card['title'] }}</span>
</div>
</x-kore::kanban.card>
Este card individual solo se usa así dentro de un board propio hecho a mano (montando kore::kanban.column tú mismo); con el componente kore::kanban normal, dale el dato extra en cada elemento de cards y decide dentro del slot qué pintar según lo que traiga.
El handler
Un único método, invocado en cada drop, dentro o entre columnas.
moveCard($cardId, $position, $toColumn) es el nombre por defecto —cámbialo con la prop handler si ya tienes un método con ese nombre—. Se dispara tanto al reordenar dentro de una columna como al mover una tarjeta a otra: $toColumn siempre trae la columna destino, y $position el índice donde quedó dentro de ella. Persiste el cambio y en el siguiente render vuelves a exponer las tarjetas actualizadas.
wire:key por tarjeta. El board pone wire:key="kore-card-{id}" en cada tarjeta automáticamente, para que el morphing de Livewire reconcilie bien tras un drop. No hace falta que lo agregues tú.
Props
| Prop | Tipo | Default | Descripción |
|---|---|---|---|
columns
|
array | [] | Columnas: [[id, label, color?], ...] |
cards
|
array|Collection | [] | Tarjetas: [[id, column, title, ...], ...] |
handler
|
string | moveCard | Método Livewire invocado en el drop: (cardId, position, toColumn) |
group
|
string | config | Grupo x-sort compartido (permite arrastrar entre columnas) |
animation
|
int | 150 | Animación de arrastre, en ms |