Contact
Demo booking with time slots
Pick a day, then a slot, then confirm
Pick a day, then a slot, then confirm
Create a demo booking panel with Tailwind CSS: a left column with the host avatar, host name and role, the meeting length with a clock glyph, the timezone, and three bullet points about what the call covers. A right column shows a horizontal row of selectable day chips (weekday abbreviation over the date number) with one selected in dark, then a grid of time-slot buttons where one is disabled, and a full-width confirm button below. Stack the columns on mobile. Then add JavaScript that makes the picker behave: selecting a day highlights it and loads that day's slots — each day offers different availability, and a day with none shows a "fully booked" message — selecting a slot highlights it and clears when the day changes, and the confirm button stays disabled until both are chosen, then names the exact day and time it will book. <section class="mx-auto max-w-3xl px-6 py-16">
<div class="grid gap-8 rounded-2xl border border-neutral-200 bg-white p-8 md:grid-cols-2">
<div>
<span class="h-12 w-12 rounded-full bg-neutral-200"></span>
<h2 class="mt-4 text-lg font-semibold text-neutral-900">Product walkthrough</h2>
<p class="mt-1 text-sm text-neutral-500">with Jordan Reyes, Solutions Engineer</p>
<div class="mt-4 space-y-1.5 text-sm text-neutral-600">
<p class="flex items-center gap-2"><span class="text-neutral-400"><svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" class="inline-block h-[1em] w-[1em] shrink-0 align-[-0.125em] transition-transform"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3.5 2"/></svg></span> 30 minutes</p>
<p class="flex items-center gap-2"><span class="text-neutral-400"><svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" class="inline-block h-[1em] w-[1em] shrink-0 align-[-0.125em] transition-transform"><path d="M20 10c0 5-8 11-8 11S4 15 4 10a8 8 0 1 1 16 0Z"/><circle cx="12" cy="10" r="2.5"/></svg></span> Europe/Berlin (CET)</p>
</div>
<ul class="mt-6 space-y-2 border-t border-neutral-100 pt-6 text-sm text-neutral-600">
<li class="flex gap-2"><span class="text-neutral-900"><svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" class="inline-block h-[1em] w-[1em] shrink-0 align-[-0.125em] transition-transform"><path d="m5 12.5 4.25 4.25L19 7"/></svg></span> A live tour of your actual use case</li>
<li class="flex gap-2"><span class="text-neutral-900"><svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" class="inline-block h-[1em] w-[1em] shrink-0 align-[-0.125em] transition-transform"><path d="m5 12.5 4.25 4.25L19 7"/></svg></span> Pricing for your seat count</li>
<li class="flex gap-2"><span class="text-neutral-900"><svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" class="inline-block h-[1em] w-[1em] shrink-0 align-[-0.125em] transition-transform"><path d="m5 12.5 4.25 4.25L19 7"/></svg></span> Security and procurement questions</li>
</ul>
</div>
<div>
<p class="text-sm font-medium text-neutral-900">Choose a day</p>
<div id="days" class="mt-3 flex gap-2 overflow-x-auto pb-1">
<button data-day="Mon 18" class="shrink-0 rounded-xl border border-neutral-200 px-3.5 py-2 text-center hover:bg-neutral-50">
<span class="block text-[10px] uppercase text-neutral-400">Mon</span><span class="block text-sm font-medium text-neutral-900">18</span>
</button>
<button data-day="Tue 19" class="shrink-0 rounded-xl border border-neutral-200 px-3.5 py-2 text-center hover:bg-neutral-50">
<span class="block text-[10px] uppercase text-neutral-400">Tue</span><span class="block text-sm font-medium text-neutral-900">19</span>
</button>
<button data-day="Wed 20" class="shrink-0 rounded-xl border border-neutral-200 px-3.5 py-2 text-center hover:bg-neutral-50">
<span class="block text-[10px] uppercase text-neutral-400">Wed</span><span class="block text-sm font-medium text-neutral-900">20</span>
</button>
<button data-day="Thu 21" class="shrink-0 rounded-xl border border-neutral-200 px-3.5 py-2 text-center hover:bg-neutral-50">
<span class="block text-[10px] uppercase text-neutral-400">Thu</span><span class="block text-sm font-medium text-neutral-900">21</span>
</button>
</div>
<p class="mt-6 text-sm font-medium text-neutral-900">Available times</p>
<div id="slots" class="mt-3 grid grid-cols-2 gap-2 text-sm"></div>
<button id="confirm" disabled class="mt-5 w-full cursor-not-allowed rounded-xl bg-neutral-900 py-2.5 text-sm font-medium text-white opacity-40 hover:bg-neutral-800">Select a day and time</button>
</div>
</div>
</section> // Availability per day — "booked" slots render disabled.
var AVAILABILITY = {
"Mon 18": [["09:00", true], ["10:30", true], ["13:00", false], ["15:00", true]],
"Tue 19": [["09:00", true], ["10:30", true], ["13:00", true], ["14:30", false], ["16:00", true], ["17:30", true]],
"Wed 20": [["11:00", true], ["13:30", true], ["16:00", false]],
"Thu 21": []
};
var dayButtons = [].slice.call(document.querySelectorAll("#days [data-day]"));
var slotGrid = document.getElementById("slots");
var confirm = document.getElementById("confirm");
var DAY_ON = "shrink-0 rounded-xl bg-neutral-900 px-3.5 py-2 text-center";
var DAY_OFF = "shrink-0 rounded-xl border border-neutral-200 px-3.5 py-2 text-center hover:bg-neutral-50";
var day = null;
var time = null;
function paintDays() {
dayButtons.forEach(function (button) {
var on = button.getAttribute("data-day") === day;
button.className = on ? DAY_ON : DAY_OFF;
// The date numeral has to invert with the chip behind it.
button.children[1].className =
"block text-sm font-medium " + (on ? "text-white" : "text-neutral-900");
});
}
function paintConfirm() {
var ready = Boolean(day && time);
confirm.disabled = !ready;
confirm.classList.toggle("opacity-40", !ready);
confirm.classList.toggle("cursor-not-allowed", !ready);
confirm.textContent = ready ? "Confirm " + day + ", " + time : "Select a day and time";
}
function renderSlots() {
slotGrid.innerHTML = "";
var slots = AVAILABILITY[day] || [];
if (day && slots.length === 0) {
var none = document.createElement("p");
none.className = "col-span-2 rounded-xl bg-neutral-50 py-6 text-center text-sm text-neutral-500";
none.textContent = "Fully booked — try another day.";
slotGrid.appendChild(none);
return;
}
slots.forEach(function (slot) {
var label = slot[0];
var open = slot[1];
var button = document.createElement("button");
button.textContent = label;
if (!open) {
button.disabled = true;
button.className = "cursor-not-allowed rounded-xl border border-neutral-100 py-2.5 text-neutral-300";
} else if (label === time) {
button.className = "rounded-xl border border-neutral-900 bg-neutral-900 py-2.5 font-medium text-white";
} else {
button.className = "rounded-xl border border-neutral-200 py-2.5 text-neutral-700 hover:bg-neutral-50";
}
button.addEventListener("click", function () {
if (!open) return;
time = label;
renderSlots();
paintConfirm();
});
slotGrid.appendChild(button);
});
}
dayButtons.forEach(function (button) {
button.addEventListener("click", function () {
day = button.getAttribute("data-day");
time = null; // a slot only means something within its day
paintDays();
renderSlots();
paintConfirm();
});
});
day = "Tue 19";
paintDays();
renderSlots();
paintConfirm();