shadcn.io is not affiliated with official shadcn/ui
User List Skeleton Block for Solid
A membership directory that loads in place: six members with avatars, emails, roles and join dates, and a Follow button on each that marks the member and counts them.
Installation
Overview
Show a member directory while its people load, then swap them in without moving anything, with this user list skeleton for Solid with Ark UI. A hairline frame with a plus mark on each corner holds a band heading with the member count, how many you follow and an Invite button, over six members from Lemniscate, a club-membership manager. The heading and the Invite button are real from the first paint; each avatar, name, email, role badge, join date and Follow button is a Skeleton box that becomes the data in the same cell, row by row, when you press Load. Follow is real and local: it marks the member and counts those you follow, and Reload clears the marks. Invite does nothing here and says so. The control is an outline Button, the bands are ruled by Guides, and a polite line says what loaded. On a phone the role and join date are left out. For directories, rosters and people pickers.
FAQ
What stays local, and how do I wire it to a real query?
Nothing is fetched. The six members are typed in MEMBERS, 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 rows when they arrive. Follow would send a request; on a real list, update the row from the response. The bars are derived from the same array as the data, so keep one row component for both.
Why doesn't the page jump when the data arrives?
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 row is a fixed height, the Follow button has a fixed width and keeps its label (the pressed state adds a check and changes the fill), and the role badge has a fixed width, so no state changes a row's size. The polite line under the panel reserves two lines, so the panel is exactly as tall before, during and after loading at every width.
What does Follow do?
It toggles aria-pressed on the member's button, fills it and adds a check, and updates the "following" count in the heading. The button's visible text is Follow and its accessible name adds the member's name. Nothing is stored, and Reload clears the marks.
Why does Invite do nothing?
Inviting needs an address, a role and a request, which isn't this block's job. The button is a real control that says it isn't wired in this demo; swap its handler for your own dialog.
Is it accessible?
The region is marked busy while it loads and carries a screen-reader-only "Loading members…", 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.