Recipe: a product roadmap
Quarters as eras, teams as lanes, a line for today, an ongoing item with no end anyone would promise, and a detail line for the selection. Read-only: a roadmap is shown more often than it is edited.
Live example: A product roadmap by quarter
Loading…
Run “A product roadmap by quarter” on your own machine
Make an empty folder and put this example’s two files in it:
index.html— the page the code runs in, its markup and styles:<style> #timeline .status-done { --tl-item-fill: #d8f3dc; } #timeline .status-now { --tl-item-fill: #d6e4ff; } #timeline .status-later { --tl-item-fill: #eceff3; } </style> <div id="timeline" style="height: 300px"></div> <p class="log" id="detail" aria-live="polite">Select an item to read about it.</p>main.js— the code, as it is in the editor now, your edits included:In a terminal in that folder, install the library and Vite (it lets the browser follow the
imports), then start it:npm init -y npm install @temporeum/timeline-element npm install --save-dev vite npx viteOpen the address it prints,
http://localhost:5173/.
How it is made
- Quarters are
eradecorations, generated in a loop; the axis still finds its own ticks. - Today is a
nowdecoration. The engine never reads a clock, so the time is the host's:Date.now()in a real page, a fixed date here so the example looks the same every day. - Ongoing work is an
openitem: it reaches past the view, and nothing is packed after it in its row. - Status is a class that sets the fill.
- The detail comes from the selection: click an item, or focus it with
Taband the arrows and pressEnter.
timeline.on("selectionChanged", ({ ids }) => {
const item = items.find((candidate) => candidate.id === ids[0]);
detail.textContent = item === undefined ? "Select an item to read about it." : `${item.label}: ${item.data}`;
});From the running example example/recipe-roadmap
To let a product manager move items, add editing: { enabled: true, snapMs } and send the command events to your server — the Gantt recipe shows the undo.