Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Milestone Planner Kanban Block for React Aria

A roadmap board of sixteen tasks in milestone lanes, each lane showing a derived count of ticked tasks, a target date in words and a progress bar, with a rule that closes a complete milestone to new work.

Framework
UI library

Preview

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Overview

Plan a launch milestone by milestone with this planner for React with React Aria. A hairline frame with a plus mark on each corner holds four lanes that share their lines: Private alpha, Public beta, Launch and After launch. Each of the sixteen tasks has a Checkbox and an owner, and every lane head works out its own progress: "3 of 4 done" counts the ticked tasks in the lane, a thin bar fills to match, and "Target 30 Oct, in 18 days" reads the lane's date against one fixed "today" (Monday 12 October in this demo, with no clock). The sentence under the heading names the next milestone with work left, so ticking a task or moving one updates the lanes and the sentence together. One rule guards the roadmap: a milestone with every task done is complete and closed to new work, and the refusal says how to reopen it. A card moves three ways: drag it by its grip, focus the grip and press Space to pick it up, the arrow keys to move it, Space to drop it and Escape to cancel, or open its Dropdown Menu and choose a lane under "Move to", which is the route for a single pointer and for touch. A polite status line in the foot reports each change and Reset puts the plan back. The frame is ruled by Guides. On a phone the lanes scroll sideways in one named region with the next lane showing. For product roadmaps, release plans and any work grouped by target date.

FAQ

How do I fill it with my own milestones and tasks?

Edit COLUMNS and START. A lane has an id, a name and a target date as YYYY-MM-DD (an empty string makes a parking lane with no date); a task has an id, a title, an owner, a done flag and the column it starts in. The counts, the bars, the date words and the header sentence are all calculated from them. Change AS_OF to move the demo's "today".

How is the progress worked out?

By counting. doneOf counts the ticked tasks in a lane and the head prints it against the lane's total, and the bar's fill is that fraction. Nothing is stored beside the tasks, so moving a task or ticking one changes both lanes involved at once. A lane with no tasks shows an empty bar and "0 of 0 done".

Why was I refused when I moved a task into a milestone?

Because that milestone is complete: it has a target date and every task in it is ticked. refusalOf stops new work landing in a finished milestone, since its date has been met, and the status line tells you to untick one of its tasks to reopen it first. The parking lane has no date, so it is never complete and always takes tasks. Remove the rule if you want finished milestones to stay open.

How do I move a card without a mouse?

Tab to the grip at the start of a card, named "Move" with the card's title. Press Space or Enter to pick it up, then ArrowUp and ArrowDown to change its place, ArrowLeft and ArrowRight to go to the neighbouring lane (the arrows swap in right-to-left languages), Home and End for the first and last place, Space or Enter to drop it and Escape to put it back. Every step is announced in the status line. The tick box is a separate stop on each card.

Why is there a menu as well as the grip?

Dragging needs a held pointer and a path, which not everyone has, so each card also has a "More actions" menu with a "Move to" choice for every milestone and the current one ticked. Choosing one moves the card by the same route as a drop, so the same rule applies, puts focus on the card in its new place and says so in the status line. React Aria's menu is a group of selectable items, so the lane is chosen by selection rather than by a radio item.

What stays in the demo, and how do I save the moves?

Everything: the cards live in the component's state, nothing is sent anywhere, and a reload or Reset brings back the starting board. To save for real, call your API from act for ticks and from put for moves, the functions every change goes through. The names, jobs and dates are made up.