v0 prompt to build a to-do app
This prompt gives v0 a complete spec for a task manager: schema, optimistic toggle behavior, undo delete, and URL-backed filters. You end up with a single App Router page wired to server actions and shadcn/ui components that you can deploy to Vercel or copy into an existing Next.js project.
Last updated
Build a to-do app as a single Next.js App Router page using shadcn/ui components. Data model: a tasks table with id, title, done, due_date, priority (low, medium, high), and created_at, stored in {{database}} through server actions in app/actions.ts. Screens: the main list at /, grouped into Today, Upcoming, and Done sections, plus a slide-over Sheet for editing a task. Behaviors: add a task from a single input pinned at the top, toggle done with a Checkbox and an optimistic update so the row moves into Done before the server action resolves, inline title editing on click, and delete with an undo Toast that restores the row if clicked in time. Filter tabs for All, Active, and Completed backed by a URL query param so refresh keeps the filter. Overdue tasks get a red Badge computed from due_date on the server, not in client JavaScript. Empty state: a plain card saying no tasks yet that autofocuses the input. Error state: if a server action throws, revert the optimistic change and surface a destructive Toast with a retry button. Styling: neutral background, one accent color, roomy row height, lucide-react icons only, no illustration packs. Acceptance: adding, completing, and deleting all work in the v0 preview without a full page reload, the Done count in the header always matches the visible list, and the chosen filter survives a refresh.Customize it
Runs in your browser. Nothing you type here is sent anywhere.
Build a to-do app as a single Next.js App Router page using shadcn/ui components. Data model: a tasks table with id, title, done, due_date, priority (low, medium, high), and created_at, stored in PostgreSQL through server actions in app/actions.ts. Screens: the main list at /, grouped into Today, Upcoming, and Done sections, plus a slide-over Sheet for editing a task. Behaviors: add a task from a single input pinned at the top, toggle done with a Checkbox and an optimistic update so the row moves into Done before the server action resolves, inline title editing on click, and delete with an undo Toast that restores the row if clicked in time. Filter tabs for All, Active, and Completed backed by a URL query param so refresh keeps the filter. Overdue tasks get a red Badge computed from due_date on the server, not in client JavaScript. Empty state: a plain card saying no tasks yet that autofocuses the input. Error state: if a server action throws, revert the optimistic change and surface a destructive Toast with a retry button. Styling: neutral background, one accent color, roomy row height, lucide-react icons only, no illustration packs. Acceptance: adding, completing, and deleting all work in the v0 preview without a full page reload, the Done count in the header always matches the visible list, and the chosen filter survives a refresh.
Same task in other tools
Questions about this prompt
Will v0 actually persist tasks, or just keep them in React state?
Left unspecified, v0 often ships useState only, which resets on refresh. This prompt pins persistence to server actions and {{database}}. If the first generation still uses local state, reply with move task state into server actions and it will refactor without redesigning the UI.
How do I extend this into multiple lists or a shared team version?
Add a lists table with a name and owner, give tasks a list_id, and ask v0 for a sidebar of lists with the active one in the route, like /list/[id]. Do it as a follow-up message so the single-list version is working before you add scope.
The Done count in the header drifts from the list. What is the fix?
That means the optimistic update and the server disagree, usually because a mutation skipped revalidatePath. Ask v0 to derive the count from the same query the list renders, never a separate counter, and to revalidate after every mutation.