DEV Community

Shourya Parashar
Shourya Parashar

Posted on

KanbanFlow

I Built a Zero-Backend Kanban Board with React + TypeScript — Here's What I Learned

No server. No database. No login. Just pure React — and it actually works great.

Why I Built KanbanFlow
Every Kanban tool I used asked me to sign up, connect to a server, or pay for features I didn't need. I wanted something that just opened and worked — instantly, privately, offline.

So I built KanbanFlow — a fully-featured Kanban board that lives entirely in your browser. No account. No backend. No setup.

What It Does

  • Unlimited columns and tasks — fully customizable
  • Drag & drop task movement across columns
  • Priority tagging — High, Medium, Low, None
  • Due dates with overdue highlighting
  • Live search + priority filtering
  • Dark / Light theme toggle
  • Auto-saves to localStorage — data persists across sessions

Tech Stack

React 18 + Vite 5 + TypeScript 5 + Tailwind CSS + React Router v6

No Redux. No external state library. Just React's useState and useReducer — keeping it lean.

The Interesting Part — localStorage as a Database

Most people reach for Firebase or Supabase immediately. But for a personal productivity tool, localStorage is genuinely underrated.

// Auto-save board state on every change
useEffect(() => {
  localStorage.setItem('kanban-board', JSON.stringify(board));
}, [board]);

// Load on mount
const [board, setBoard] = useState<Board>(() => {
  const saved = localStorage.getItem('kanban-board');
  return saved ? JSON.parse(saved) : defaultBoard;
});
Enter fullscreen mode Exit fullscreen mode

This pattern gives you:

  • Instant persistence with zero latency
  • Works completely offline
  • No auth, no API keys, no cost
  • Data stays on the user's machine (privacy win)

The tradeoff? No cross-device sync. For a personal board, that's totally acceptable.

Drag & Drop Without a Library

Instead of reaching for react-beautiful-dnd or dnd-kit, I implemented drag and drop using the native HTML5 Drag and Drop API — which kept the bundle size tiny.

const handleDragStart = (e: DragEvent, taskId: string) => {
  e.dataTransfer.setData('taskId', taskId);
};

const handleDrop = (e: DragEvent, targetColumnId: string) => {
  const taskId = e.dataTransfer.getData('taskId');
  moveTask(taskId, targetColumnId);
};
Enter fullscreen mode Exit fullscreen mode

Project Structure

I kept the component tree flat and predictable:

src/
├── types/kanban.ts         # All types + constants
├── components/kanban/
│   ├── TaskCard.tsx
│   ├── KanbanColumn.tsx
│   ├── TaskForm.tsx
│   ├── Header.tsx
│   └── Toolbar.tsx
└── pages/
    └── Index.tsx           # Main orchestrator
Enter fullscreen mode Exit fullscreen mode

One rule I followed: no component does more than one thing. KanbanColumn renders a column. TaskCard renders a card. Index.tsx wires them together.


Try It

Live: kanbanflow.shouryaparashar.in
GitHub: github.com/im-shourya/KanbanFlow

Built by Shourya Parashar — Full Stack Developer.

If you found this useful, drop a ⭐ on GitHub — it genuinely helps!

Top comments (0)