Build a goal selection onboarding step with Tailwind CSS. Centre a max-w-2xl column with a step label, a heading asking what the person wants to do first, and a muted line saying they can pick more than one. Below, a grid of nine selectable chips laid out two or three per row: each is a bordered rounded-xl button with a glyph tile, a short label and a muted one-line description, and when selected it gains a neutral-900 border, a soft neutral-50 background and a small check badge in the corner. Under the grid, a live line reading how many are selected with a minimum of one, and a footer with a ghost "Skip" and a dark Continue button that stays disabled until at least one chip is chosen. Then add JavaScript that toggles selection, caps the choice at four with a small inline note when the cap is reached, and keeps the counter and button state in sync.
Paste it into Claude, Cursor, v0 or any AI coding tool. Prefer the
finished markup? .
Build a goal selection onboarding step with Tailwind CSS. Centre a max-w-2xl column with a step label, a heading asking what the person wants to do first, and a muted line saying they can pick more than one. Below, a grid of nine selectable chips laid out two or three per row: each is a bordered rounded-xl button with a glyph tile, a short label and a muted one-line description, and when selected it gains a neutral-900 border, a soft neutral-50 background and a small check badge in the corner. Under the grid, a live line reading how many are selected with a minimum of one, and a footer with a ghost "Skip" and a dark Continue button that stays disabled until at least one chip is chosen. Then add JavaScript that toggles selection, caps the choice at four with a small inline note when the cap is reached, and keeps the counter and button state in sync.
var MAX = 4;
var goals = Array.prototype.slice.call(document.querySelectorAll(".goal"));
var counter = document.getElementById("goalCounter");
var next = document.getElementById("goalContinue");
var chosen = [];
function badge(el) {
var mark = document.createElement("span");
mark.className = "goal-check absolute right-3 top-3 grid h-5 w-5 place-items-center rounded-full bg-neutral-900 text-[10px] text-white";
mark.textContent = "✓";
el.appendChild(mark);
}
function sync() {
goals.forEach(function (g) {
var on = chosen.indexOf(g.dataset.goal) !== -1;
g.classList.toggle("border-neutral-900", on);
g.classList.toggle("bg-neutral-50", on);
g.classList.toggle("border-neutral-200", !on);
var mark = g.querySelector(".goal-check");
if (on && !mark) badge(g);
if (!on && mark) mark.remove();
});
if (chosen.length === 0) counter.textContent = "Nothing selected yet — pick at least one.";
else if (chosen.length === MAX) counter.textContent = chosen.length + " of " + MAX + " selected · that is the maximum, deselect one to swap.";
else counter.textContent = chosen.length + " of " + MAX + " selected.";
var ok = chosen.length > 0;
next.disabled = !ok;
next.classList.toggle("opacity-40", !ok);
next.classList.toggle("cursor-not-allowed", !ok);
}
goals.forEach(function (goal) {
goal.addEventListener("click", function () {
var key = goal.dataset.goal;
var at = chosen.indexOf(key);
if (at !== -1) chosen.splice(at, 1);
else if (chosen.length < MAX) chosen.push(key);
sync();
});
});
sync();