AJ
Back to Builds
DesktopComplete

Task Manager

A local-first desktop task app with multi-list support, inline editing, due dates, and JSON-based persistence. Custom titlebar, three-pane layout, and cross-platform packaging via Electron Builder.

ElectronReact 19Vite

Overview

Task Manager is a Microsoft To Do-style desktop application built with Electron, React, and Vite. It has a three-pane layout (sidebar with lists, main task list, details pane), persistent local storage via a JSON file in the OS app data folder, and a fully frameless window with a custom React-rendered title bar. A compiled Windows portable executable lives in the repo.

Why it was built

A personal tool, built for actual daily use. The app ID is com.antigravity.taskmanagermvp and it's already shipped as a Windows portable, meaning it was built, used, and found good enough to keep. The goal was to learn Electron's IPC architecture while making something genuinely useful, not just a tutorial project.

Multiple Task Lists

The sidebar shows all lists. Lists are created by pressing Enter on a name input that auto-focuses, auto-cancels on Escape or blur. Each task carries a listId foreign key so filtering is a simple array.filter() call.

Local JSON Persistence via IPC

Data is read on mount and written on every state change via window.electronAPI.readData() and writeData(). The JSON file lives at %APPDATA%\Task Manager MVP\tasks_data.json. A default 'My Tasks' list bootstraps on first run.

Inline Task Editing

Each task row renders a live input for the title, allowing direct editing without entering a separate edit mode. The checkbox and delete button both use e.stopPropagation() to prevent triggering row selection on the parent.

Tech Breakdown

Electron

Required to access the filesystem for local persistence and to ship a native .exe with a custom frameless window. A web app cannot write to %APPDATA% directly.

Vite

The dev script runs Vite and Electron concurrently via wait-on tcp:3000. Vite's HMR is significantly faster than CRA inside Electron dev, where you can't just reload a browser tab.

React 19

Used purely as the UI layer. All state lives in App.jsx, no external state library needed because the data model (lists + tasks) is simple enough to not justify one.

contextBridge (Electron)

nodeIntegration is false, contextIsolation is true. The preload script exposes only 5 specific IPC calls to the renderer, not the full Node.js API. This is the correct modern Electron security pattern.

Challenges
  • 1

    Wiring the custom frameless title bar required coordinating frame: false in the main process, IPC handlers for each window control, and Segoe MDL2 icon rendering via CSS, and this only works correctly on Windows where that font is available system-wide.

  • 2

    Auto-save on every state change means the useEffect that calls writeData fires on every keystroke in a task title. The condition data.lists.length > 0 prevents writing before the initial load completes, but there is a brief race window at mount.

What's Next

The MVP is done and in daily use. The natural next features are task reordering via drag-and-drop, priority levels with colour coding, a global search across all lists, and eventually optional cloud sync, probably via a lightweight SQLite + sync solution rather than a full backend.

Want to know more?

Happy to walk you through the details, just reach out.