shadcn.io is not affiliated with official shadcn/ui
Week Calendar Skeleton Block for Vue
A meeting-room week from Monday to Sunday that loads in place: real day heads and hour lines under ten booking boxes that become titles, people and times, day by day.
Installation
Overview
Show a week of bookings while they load, then swap them in without moving anything, with this week calendar skeleton for Vue with Ark UI. A hairline frame with a plus mark on each corner holds a band with the week's dates and a previous and a next button, over a timetable of seven day heads and the hours 08:00 to 17:00 for Schist, a meeting-room booking tool. The week, the day heads, the hour labels and the hour lines are real from the first paint; each of the ten bookings is a Skeleton box spanning the same half hours that becomes the title, the person and the time range in the same place, day by day, when you press Load. The arrows reload the neighbouring typed week. On a phone the week pans sideways in a snap scroller, about three days at a time, with the hour labels pinned. It's built from Skeleton, Button and Guides, with a CSS entrance only. For room and resource booking, rotas and any week view that waits for a query.
FAQ
What stays local, and how do I wire it to a real query?
Nothing is fetched. The two weeks of bookings are typed in WEEKS, Load starts a 700 millisecond timer, and when it ends the phase becomes ready and the data swaps in; Reload goes back to the bars and in again. To wire it for real, delete the timer, the Load button and the polite line, and set data-state (loading or ready) and aria-busy on the region from your query's pending state, or use the bars as a Suspense fallback and render the real bookings when they arrive. The bars are derived from the same array as the data, so keep one component for both.
Does the timetable keep its size while it loads?
Each bar and its data sit in one grid cell, so the larger of the two sets the cell's box and the swap changes nothing around it. The timetable is a fixed grid of 20 half-hour rows under a fixed head row, the bookings sit in a subgrid by two CSS variables, and each booking's box and its text share one cell. The heads, labels and frame are real in both phases, and the polite line reserves two lines, so the block is exactly as tall before, during and after loading at every width.
How does the week look on a phone?
The grid keeps a minimum width inside a scroller that a keyboard can focus and pan, so about three days show at a time and the rest are a swipe away. The hour labels are pinned to the start edge with a solid background, so they stay in view while the days move under them. The pin follows the reading direction.
What do the previous and next buttons do?
They reload the neighbouring week: the block holds 2 typed weeks (12 to 18 and 19 to 25 October 2026), and pressing an arrow goes back to the bars and then to that week's data. At the first or last week the press does nothing but say so in the polite line. Nothing else is interactive: you can't create or move anything here. In your app, set the week in your router or state and let your query fall back to the bars while it loads.
Is it accessible?
The region is marked busy while it loads and carries a screen-reader-only "Loading bookings…", and the polite line announces what loaded once. The bars are hidden from assistive technology and the layer that isn't showing is invisible, so it is neither read nor focusable. The pulse stops when the data is in, and under reduced motion there is no pulse, no spinner and no stagger: the swap is instant. The bookings are an ordered list named for the week, each with its own time, and the scroller is named "Week grid".