shadcn.io is not affiliated with official shadcn/ui
Booking Slots Calendar Block for Vue
A booking page where the day's start times are worked out from opening hours, existing bookings, a buffer and four hours' notice, with the reason a time is missing and a Confirm that ends in a receipt.
Installation
Overview
Let people book a visit without a double booking, with this booking slots calendar for Vue with Ark UI. A hairline frame with a plus mark on each corner puts the Calendar at the start (October to December 2026, Monday first) and the chosen day's start times at the end. Weekends, past days and fully booked days are struck in the calendar, and a dot under a day means it still has a time to offer. The starts are never typed as available: every half hour from 09:00 is checked against the studio's hours, the bookings already made, a 15-minute buffer on both sides and four hours' notice from the block's fixed "now" (14 October, 10:30 studio time, UTC+1). A Toggle Group switches the visit between 30 and 60 minutes and the whole grid is worked out again. A time that is not offered stays in the grid, struck, and a Collapsible called "Why are some times missing?" lists each with its reason (Booked, 15-minute buffer, Within 4 hours' notice or After closing). Choosing a time fills the foot, and the Shine Button Confirm turns it into a receipt with Undo. The bands are ruled by Guides. It's built from Calendar, Toggle Group, Collapsible, Button, Shine Button and Guides, with a CSS entrance only. For studios, clinics, tutors and any page that sells a time.
FAQ
How are the available times worked out?
reasonOf(day, start, length) decides every start in the grid. A start is closed when the visit would run past closing time (closeOf), within the notice period when it is today and earlier than now plus four hours, booked when it overlaps an entry of BUSY, and buffered when it only overlaps the 15 minutes either side of one. Everything else is open. Edit BUSY_LINES, closeOf, NOTICE_MIN and BUFFER_MIN to match your own rules; the grid, the counts, the struck days and the reasons all follow.
Why show the times that are not offered?
A booking page that quietly leaves out 10:00 leaves people wondering whether it is broken. Here every start stays in the grid, struck through and announced as "not offered" with its reason, and the Collapsible lists them all in words. Nothing about availability is shown by colour alone.
Which time zone is it, and why is now always 14 October?
Studio time, fixed at UTC+1 and said in the header; nothing converts to the visitor's zone. Nothing in the block reads the clock either: AS_OF is the one moment it treats as now, so the notice rule and the ring on today look the same on any day and in a screenshot. To follow the real date, set AS_OF from your server and keep the rest.
How do the struck days work on each library?
What stays local, and how do I wire it up?
Everything. Confirm only changes state in the page: the receipt says "in this demo" and no invite, email or booking is created, and Undo takes it back. To make it real, load the busy blocks for the visible month from your calendar API into BUSY, and post the chosen day, start and length from confirm; the confirmed time should then be re-checked on the server, because another visitor may have taken it.