A single-list todo app built with Next.js 16, TypeScript, and Tailwind CSS v4.
- Node.js 20 or later (Next.js 16 requirement)
- npm (or pnpm / yarn / bun)
npm install# Start the dev server
npm run dev
# Production build
npm run build
# Start the production server
npm run start
# Lint
npm run lint
# Run unit tests (lib helpers)
npm run testOpen http://localhost:3000.
- Single todo list with renameable title (modal dialog)
- Add / edit / delete / toggle tasks
- Sort: Manual, A→Z, Z→A
- Manual reorder via Move Up / Down buttons and drag-and-drop (
@dnd-kit, keyboard-accessible) - Real-time, case-insensitive search
- Status filter: All / Active / Done
- Progress indicator with animated bar
- Toast notifications (success + undo for delete)
- LocalStorage persistence
- Search, sort, and status filter synced to URL query params (
?q=,?sort=,?status=) - Friendly empty states, responsive layout, focus rings, ARIA labels
- State:
useReducer+ Context (src/context/TodoContext.tsx). All mutations go through one reducer, the reducer is pure and testable. Items are stored in canonical (manual) order, A→Z / Z→A are derived view transformations, so toggling sort never loses the user's manual order. - Persistence: LocalStorage (validated on read) for title / items / sortMode. URL params for search query and sort mode (URL takes precedence on load).
- UI primitives:
src/components/ui/(Button, IconButton, Input, Checkbox, Modal, Toast). Application components compose these. - Modals: portal-mounted, focus-trapped, ESC/backdrop to close, focus restored to the opener on close.
- No backend — all state is client-side.
src/
├── app/ # Next.js App Router (layout, page, globals.css)
├── components/
│ ├── ui/ # Presentational primitives
│ └── *.tsx # Feature components
├── context/ # TodoContext, ToastContext
├── lib/ # Pure utility helpers (sort, filter, storage, url, id)
└── types/ # Shared TypeScript types