Kanban & Board Variants
16 production-ready boards — pick one, see the live preview, copy the code
Personal Tasks
Simple to-do board with three lanes.
JSON Configuration
3 columns · 4 cardsInstall & set up
Everything this board needs: 7 generated files to copy and 14 shared engine files the CLI can install for you.
Choose how data is fetched
Two independent choices. The default adds no dependency at all — the command below and the code both follow whatever you pick.
HTTP client — used by services.ts
Where results live — used by hooks.ts
Adds no extra packages.
Install it with the CLI
Installs every file below and its packages in one command. The steps after this are only for doing it by hand.
npx afnoui add kanban/kanban-personal-tasksOr install the packages yourself
Only needed if you copied the files by hand instead of running the command above.
Runtime dependencies
npm install react react-dom lucide-react clsx tailwind-merge class-variance-authorityDev dependencies
None — nothing extra is needed at build time.
- Requires AfnoUI components: button, badge, input, label, textarea, select, dialog, scroll-area, avatar, progress, use-toast.
- Bring `cn` from your `@/lib/utils` (clsx + tailwind-merge).
- DnD library is bundled — no @dnd-kit dependency.
- Import components/dnd/dnd.css once at app entry (e.g. in your global stylesheet).
Generated files
Generated files are yours to copy and edit; shared engine files are installed once and reused.
Generated per board(7)
Shared engine — copy once(14)
Your generated board component — wires the engine to your config + data + onChange hook.
import { useState } from "react";
import { KanbanBoard } from "@/components/kanban/KanbanBoard";
import { boardConfig } from "./config";
import { initialCards } from "./data";
import { useMyTasksCardChange, useMyTasksLoadMore } from "./hooks";
import type { KanbanCardData } from "./types";
/**
* My Tasks
* Personal productivity board
*
* Drag-and-drop is powered by the project's custom Pointer DnD library
* (no @dnd-kit dependency). Cards persist locally — wire `services.ts`
* to your backend to make moves stick across reloads.
*/
export default function MyTasks() {
const [cards, setCards] = useState<KanbanCardData[]>(initialCards);
const handleCardChange = useMyTasksCardChange();
const handleLoadMore = useMyTasksLoadMore();
return (
<div className="space-y-4">
<div>
<h2 className="text-xl font-bold">{boardConfig.title}</h2>
{boardConfig.subtitle && (
<p className="text-sm text-muted-foreground">{boardConfig.subtitle}</p>
)}
</div>
<KanbanBoard
config={boardConfig}
cards={cards}
onCardsChange={setCards}
onCardChange={handleCardChange}
onLoadMore={handleLoadMore}
/>
</div>
);
}