Summit
ComponentsFeedback

Skeleton

A Skeleton shows users where content will appear while it is loading.

When to Use

  • for content whose layout is known before it loads, such as a row with an Avatar and two lines of text
  • for the items of a Sidebar menu while the menu loads, as SidebarMenuSkeleton in Sidebar does

When Not to Use

  • for a wait in a small part, such as a Badge (use a Spinner)
  • for a task whose progress can be measured (use the Progress component)
  • for a request that a Button started (use a Loading Button)
  • for content that is missing and not on its way (use the Empty component)

See Progress for a comparison of the Spinner, the Progress component, and the Skeleton.

Behavior

A Skeleton has no size of its own, so set the height, the width, and the radius of the content that it replaces. In the preview, size-10 rounded-full is set for an Avatar and h-4 for a line of text.

Use one Skeleton for one piece of content so that the row keeps its shape when the content arrives.

DoUse a separate Skeleton for each piece of content, at the size of that content.
Don’tWhen one block covers the row, users can’t see what is coming, and the row changes shape when the content loads.

Accessibility

A Skeleton isn’t focusable and has no role and no text, so screen readers announce nothing in its place.

To tell assistive technology that a region is loading, set aria-busy="true" on it, and remove the attribute when the content arrives. ARIA 1.2 defines aria-busy for an element that is being modified.

Installation

npx shadcn@latest add @summit/skeleton

Usage

Set the size with classes.

import { Skeleton } from '@/components/ui/skeleton';

<Skeleton className="h-4 w-56" />;

In the Shape of a Row

To match a row, use one Skeleton for each piece of content.

In the Shape of a Row
<div className="flex items-center gap-4">
    <Skeleton className="size-10 rounded-full" />
    <div className="grid gap-2">
        <Skeleton className="h-4 w-56" />
        <Skeleton className="h-4 w-40" />
    </div>
</div>

While a Region Loads

Set aria-busy on the region while it shows Skeletons.

While a Region Loads
<section aria-busy={loading}>{loading ? <Skeleton className="h-4 w-56" /> : <p>{client.name}</p>}</section>

API Reference

Skeleton adds no props. All props are passed to its div.

On this page