Skeleton
Overview
A placeholder used to indicate that content is still loading. SSkeleton combines the Aria Skeleton primitive (zero styles) with the skeletonVariants style recipe (6 sizes × 2 shapes × animated toggle) and is decorative (aria-hidden by default).
Use it to reserve space and reduce layout shift while data loads — cards, tables, lists, and detail blocks. Prefer spinner for an indefinite “please wait” on an action, and empty for the final no-data state.
Usage
Features
- 🧩 Aria/styled split — the Aria
Skeletonprimitive ownsaria-hidden/as/asChild;SSkeletoninjectsskeletonVariants - 📐 6 size presets — xs–2xl that set both height and width
- 🟦 2 shapes —
auto(rounded) androunded(pill/circle) - ⚡ Animated —
animate-pulseby default; setanimated=falsefor a static block - ♿ Decorative by default —
aria-hidden="true"unless overridden, so it never confuses assistive tech - 🔧 Polymorphic —
as/asChildto render as any element - 🎛️ Custom sizing — override dimensions via
classfor bespoke placeholders
Component family
SSkeleton(styled) — the entry wrapper;skeletonVariantsrecipeSkeleton(Aria) — the state-free primitive;aria-hiddendefault +as/asChild
Demos
Basic
Custom Size
API
Aria Layer
1Skeleton
Props
| Prop | Type | Default | Description |
|---|---|---|---|
class | ClassValue | — | Additional class names applied to the root element. |
size | ThemeSize | — | Visual size of the component. |
animated | boolean | — | Whether the skeleton should have an animation effect. Defaults to `true`. |
shape | SkeletonShape | — | Shape of the component. |
asChild | boolean | — | Change the default rendered element for the one passed as a child, merging their props and behavior. |
as | AsTag | Component | 'div' | The element or component this component should render as. Can be overwrite by `asChild` |
Notes
Architecture and benchmark differences
The Aria Skeleton is a state-free primitive that only owns the decorative aria-hidden default and polymorphism, while SSkeleton keeps all styling in skeletonVariants. This mirrors shadcn/ui’s headless/styled split, unlike Ant Design, Element Plus, Mantine and Naive UI which ship a single styled skeleton with paragraph/avatar/title composition props. VeanUI stays minimal (one primitive) and expects consumers to compose placeholders with grid/flex — the size scale and rounded pill shape cover the common cases the single-package libraries expose as presets.
| Capability | VeanUI | shadcn/ui | Ant Design Skeleton | Element Plus Skeleton | Mantine Skeleton | Naive UI Skeleton |
|---|---|---|---|---|---|---|
| Aria/styled split | ✅ | ✅ | — | — | — | — |
| Animated pulse | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Size variants (6) | ✅ | — | — | ✅ | ✅ | — |
| Shape (rounded / pill) | ✅ | — | — | — | — | — |
aria-hidden by default | ✅ | — | — | — | — | — |
as/asChild | ✅ | ✅ | — | — | — | — |
— = unsupported or a different interaction model.
Cautions
SSkeletonis decorative andaria-hiddenby default. If the placeholder carries meaning, put a visually-hidden label (or real content once loaded) in an accessible container.animateddefaults totrue(ananimate-pulse). Setanimated="false"for a static block to avoid motion.- The
sizepresets set both width and height; useclass(e.g.w-full h-32) to customize dimensions. - Compose multiple
SSkeletonblocks with your own layout (flex/grid) for card/table-shaped placeholders. - Rendered as a
<div>by default; useas/asChildwhen a different element is required.
Roadmap
No blocking gaps identified for the core skeleton API. Composed skeleton blocks (title/avatar/paragraph) are left to consumer composition rather than shipped as presets.
FAQ
How do I render a circular skeleton?
Use shape="rounded":
<SSkeleton shape="rounded" class="size-12" />How do I disable the animation?
Set animated="false":
<SSkeleton :animated="false" />How do I set a custom size?
Override with class (the presets only set defaults):
<SSkeleton class="h-16 w-full" />Is it accessible?
Yes — SSkeleton is aria-hidden by default so screen readers ignore it. If the loading state is meaningful, wrap it with an aria-live/aria-label container and replace it with real content when ready.
How do I build a card-shaped placeholder?
Compose several blocks with your own layout:
<div class="space-y-3 rounded-md border p-4">
<SSkeleton class="h-6 w-1/3" />
<SSkeleton class="h-4 w-full" />
<SSkeleton class="h-4 w-2/3" />
</div>