Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Sidebar Menu Skeleton Block for React Aria

A role-based admin menu that loads in place: the mark and the Workspace and Admin labels stay while eight items with icons, labels and counts, and the signed-in person, become data.

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 menu while the items a role may see load, with this sidebar menu skeleton for React with React Aria. A hairline card with a plus mark on each corner holds a navigation from Envoi, an admin console: the mark and name, two ruled groups (Workspace and Admin) of four rows each, and the signed-in person at the foot. The mark, the group labels and the frame are real from the first paint; each row's icon, label and count, and the person's initials, name and role, are Skeleton bars that become the data in the same cell, row by row, because the role decides which items it gets. The current item is marked, and pressing an item says it is not wired in this demo. It is plain markup, not the catalog Sidebar. It's built from Skeleton, Avatar, Button and Guides, with a CSS entrance only. For admin consoles, back offices and any menu that depends on who you are.

FAQ

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

Nothing is fetched. The eight items and the person are typed in GROUPS, 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 items when they arrive. The bars are derived from the same data as the real content, so keep one component for both.

Does the card keep its height 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 frame, the mark, the group labels and the person's frame are real in both phases, and the polite line reserves two lines, so the panel is exactly as tall before, during and after loading at every width.

How does the role decide the items?

In your app the server sends only the items the signed-in role may open, and the menu renders that list. Here the Support lead's eight items are typed in GROUPS; to show another role, change the array. Never rely on hiding an item for security: check the permission on the server for every route.

Is it accessible?

The region is marked busy while it loads and carries a screen-reader-only "Loading menu…", 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 navigation is named for the product, each group's list is named by its label, and each row's name carries its count ("Orders, 14") with the visible number hidden so it is not read twice.

What if an item has no count?

A count of 0 shows no number and its name is just the label, while the cell keeps its width, so the labels stay aligned. Add a state to the data, such as a dot for unread, and the row needs no other change.