Skip to content
Framework: Vite + React + TypeScriptDifficulty: beginner

Todo, kanban and notes

A productivity app with a todo list, a drag-and-drop kanban board, and a notes editor sharing one local dataset.

Three views over persisted local state: a classic todo list with completion and filtering, a three-column board with HTML5 drag-and-drop plus keyboard-friendly move buttons, and a two-pane notes editor. Everything is typed and saved to localStorage through a tiny hook, which makes it a good base for learning state management before adding a database.

  • react
  • todo
  • kanban
  • notes
  • productivity
  • tailwind

This preview is the template's actual file tree and source code — exactly what is copied into a new project. Codexa does not publish screenshots or mock-ups of templates; run the project to see it rendered.

Files14 files

src/views/Board.tsx59 lines
import { useState } from "react";
import { COLUMNS, COLUMN_LABEL, newId, type Column, type Task } from "../types";

type Props = { tasks: Task[]; setTasks: (next: Task[] | ((prev: Task[]) => Task[])) => void };

export function Board({ tasks, setTasks }: Props) {
  const [dragging, setDragging] = useState<string | null>(null);
  const move = (id: string, column: Column) => setTasks((prev) => prev.map((t) => (t.id === id ? { ...t, column } : t)));
  const addTo = (column: Column) => {
    const title = window.prompt("Task title");
    if (title?.trim()) setTasks((prev) => [...prev, { id: newId(), title: title.trim(), column, createdAt: Date.now() }]);
  };

  return (
    <div className="grid gap-4 md:grid-cols-3">
      {COLUMNS.map((col) => (
        <section
          key={col}
          aria-labelledby={"col-" + col}
          onDragOver={(e) => e.preventDefault()}
          onDrop={() => {
            if (dragging) move(dragging, col);
            setDragging(null);
          }}
          className="flex min-h-48 flex-col rounded-xl border border-slate-200 bg-white p-3"
        >
          <div className="flex items-center justify-between">
            <h2 id={"col-" + col} className="text-sm font-medium">
              {COLUMN_LABEL[col]} <span className="text-slate-400">{tasks.filter((t) => t.column === col).length}</span>
            </h2>
            <button type="button" onClick={() => addTo(col)} className="text-xs text-blue-600 hover:underline">
              + Add
            </button>
          </div>
          <ul className="mt-3 flex-1 space-y-2">
            {tasks
              .filter((t) => t.column === col)
              .map((t) => {
                const i = COLUMNS.indexOf(col);
                return (
                  <li key={t.id} draggable onDragStart={() => setDragging(t.id)} onDragEnd={() => setDragging(null)} className="cursor-grab rounded-lg border border-slate-200 bg-slate-50 p-3 text-sm active:cursor-grabbing">
                    <p>{t.title}</p>
                    <div className="mt-2 flex justify-between">
                      <button type="button" disabled={i === 0} onClick={() => move(t.id, COLUMNS[i - 1] ?? col)} className="text-xs text-slate-500 disabled:opacity-30" aria-label={"Move " + t.title + " to " + (COLUMN_LABEL[COLUMNS[i - 1] ?? col])}>
                        ← Back
                      </button>
                      <button type="button" disabled={i === COLUMNS.length - 1} onClick={() => move(t.id, COLUMNS[i + 1] ?? col)} className="text-xs text-slate-500 disabled:opacity-30" aria-label={"Move " + t.title + " to " + (COLUMN_LABEL[COLUMNS[i + 1] ?? col])}>
                        Forward →
                      </button>
                    </div>
                  </li>
                );
              })}
          </ul>
        </section>
      ))}
    </div>
  );
}

Dependencies

Documented from the template's package.json. The runtime has a prebuilt dependency set for Vite + React + TypeScript, so installs are fast.

PackageVersion
react^19.1.0
react-dom^19.1.0
vite^6.3.0
@vitejs/plugin-react^4.4.0
tailwindcss^4.1.0
@tailwindcss/vite^4.1.0
typescript^5.8.0

How it runs

Framework
Vite + React + TypeScript
Dev command
npm run dev
Build command
npm run build
Output directory
dist
Port
5173
Opens at
/
Difficulty
beginner

Projects run in an isolated sandbox with a live preview. Read the projects documentation for details on settings, snapshots and deployment.

View all
  • Framework: Vite + React + TypeScriptDifficulty: beginner
    Featured

    React starter

    A clean React + TypeScript + Tailwind single-page app. The default target for AI generation.

    • react
    • typescript
    • tailwind
    • vite
    • spa

    9 files

  • Framework: Node.js + ExpressDifficulty: intermediate

    Express REST API

    A TypeScript Express API with routing, validation, and an in-memory store you can swap for PostgreSQL.

    • node
    • express
    • api
    • typescript
    • backend

    5 files

  • Framework: Node.js + ExpressDifficulty: intermediate

    Structured Express API

    A notes REST API split into router, middleware, and store modules, with logging, error handling, and search.

    • node
    • express
    • api
    • rest
    • typescript

    8 files

Need the raw data? GET /api/v1/templates/vite-react-tasks returns this template with its files.

Build on Todo, kanban and notes

Create a free account, start from this template, and ask the AI agent to turn it into your app.