Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Month Calendar Skeleton Block for Svelte

A month of crew shifts with an agenda beside it that loads in place: real day numbers and weekday heads, shift dots and a Coming up list that fill in week by week.

Framework
UI library

Preview

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Overview

Show a month while its shifts load, then swap them in without moving anything, with this month calendar skeleton for Svelte with Ark UI. A hairline frame with a plus mark on each corner holds a band with the month's name, the shift count and a previous and a next button, over a native table of seven weekday heads and five weeks for Pumice, a crew-shift planner, with an agenda cell beside it. The month name, the weekday heads and all 35 day numbers are real from the first paint (the neighbouring months' days in a quiet muted text, the typed today in a solid chip); the dots that count each day's shifts, the count and the four "Coming up" events are Skeleton bars that become the data in the same cell, week by week, when you press Load. The arrows reload the neighbouring typed month. On a phone the agenda stacks under the grid. It's built from Skeleton, Button and Guides, with a CSS entrance only. For planners, rotas and any month view that waits for a query.

FAQ

What stays local, and how do I wire it to a real query?

Nothing is fetched. The three months of shifts are typed in MONTHS, 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 shifts and events when they arrive. The bars are derived from the same array as the data, so keep one component for both.

Does the grid 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. Every month is drawn as five weeks starting on Sunday (September, October and November 2026 all fit), the rows have a fixed height, and a day's dots and its bar 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 do the dots say how many shifts a day has?

One dot per shift, up to three, and a screen-reader-only "2 shifts" in the same cell, so the count never depends on counting dots. The dots are the foreground color, not a palette color. Days from the neighbouring months have no dots because they belong to another month's data.

What do the previous and next buttons do?

They reload the neighbouring month: the block holds 3 typed months (September, October and November 2026), and pressing an arrow goes back to the bars and then to that month's data. At the first or last month 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 month 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 shifts…", 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 grid is a real table with a caption and column heads, and the typed today carries aria-current="date".