shadcn.io is not affiliated with official shadcn/ui
App Shell Skeleton Block for Radix UI
A project-management app that loads in place: the icon rail, top bar and section headings stay while the breadcrumb, overview, four tasks and side details become data, main column first.
Installation
Overview
Show a whole app while its project loads, then swap the data in without moving anything, with this app shell skeleton for React with Radix UI. A hairline window with a plus mark on each corner holds an icon rail of six links, a top bar with the Projects heading, a search box, an outline Load Button and the signed-in person, and a two-column page from Catenary, a project-management app. The rail, the section headings (Overview, Tasks, Details, Activity) and the search box are real from the first paint; the breadcrumb, the project title, four overview lines, four tasks with their icon tile, two lines and more button, a facts list and three activity items are Skeleton bars that become the data in the same cell, the main column first and then the side column, when you press Load. The rail links, the search box and the more buttons say they are not wired in this demo. On a phone the rail stays narrow and the side column stacks under the main one. It's built from Skeleton, Avatar, Input, Button and Guides, with a CSS entrance only. For project tools, admin consoles and any screen with a rail.
FAQ
What stays local, and how do I wire it to a real query?
Nothing is fetched. The project, its overview lines, four tasks, facts and activity are typed in TASKS, 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 page when they arrive. The bars are derived from the same data as the real content, so keep one component for both.
Does the window keep its height while it loads?
The window has a fixed height (h-[36rem], md:h-[46rem]) and only its page scrolls, never the window or the host page. Each bar and its data sit in one grid cell, so the larger of the two sets the cell's box, and the rail, the top bar and the section headings are real in both phases. Nothing is added or removed when the data arrives, so the window is exactly as tall and every control is where it was before, during and after loading.
How does the rail work without the catalog Sidebar?
It is plain markup: an aside with a nav named for the product and a list of icon buttons, each with an aria-label, the current one marked aria-current="page". A skeleton's feature is the loading page, not the sidebar's collapse or its phone sheet, so the rail stays a fixed 48 pixel strip at every width. Use the catalog Sidebar when you need the rail to expand.
Is it accessible?
The region is marked busy while it loads and carries a screen-reader-only "Loading project…", 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 page is a labelled scroll region the keyboard can focus, the rail buttons are named, and each task's more button is named for the task.