Skip to content

Skeleton

A pulsing placeholder that preserves layout while content loads.

Stablev0.4.2added in v0.1.0@garn/ui/skeleton
On this page

Default

A card placeholder (avatar + two lines).

Installation

garn is copy-in — the garn CLI writes this component's source into your project, so you own and can edit it. It resolves any base files and installs the npm dependencies below for you.

terminal
npx garn-ui add skeleton
First time? Set up garn in your project
Registry
skeleton
Deps
None
Registry deps
utils

Import

import { Skeleton } from "@garn/ui/skeleton";

Props

The component's public props and their types.

No component-specific props — this is a thin wrapper over its native element.

Styling

Target these data-slots and states, and remap these tokens, to restyle without forking the component.

[data-slot="skeleton"]

States

SelectorState
.animate-pulsepulse

When to use

Hold the page's shape while content loads — mirror the size/shape of the incoming text or media.

Reach for something else when

  • An indeterminate spinner inside a control (use spinner)
  • a blank state with nothing to load (use empty).

Overview

Skeleton holds the page's shape while content loads, mirroring the size and shape of the incoming text or media so the layout doesn't jump when data arrives. It's the right loading pattern when you know the structure ahead of time — a list, a card, a profile. For an indeterminate spot with no known shape use a Spinner, and for a genuinely empty result (not loading) use Empty.

Guidelines

Shape the skeleton like the real content. Match the blocks to the text lines, avatar, and media that will replace them so the swap is seamless — a generic grey box that resizes on load defeats the purpose. Reuse the real layout's spacing.

Use it for structured, short waits. Skeletons suit content whose shape you can predict; for an unknown or very brief wait, a Spinner is simpler. Don't leave skeletons up indefinitely — fall through to an error or empty state if the load fails.

Keep it quiet and accessible. Mark the placeholder region aria-busy (and hide the decorative shapes from screen readers) so assistive tech announces "loading" rather than reading empty boxes. Keep the shimmer subtle and respect reduced-motion.

Best practices

Do
  • Match the skeleton's dimensions to the real content to avoid layout shift.
  • Wrap the loading region in aria-busy and swap to content when ready.
Don't
  • Don't leave skeletons up indefinitely on error — show an error/empty state.
  • Don't animate so strongly it distracts.

Content guidelines

  • Skeletons carry no copy — mark the loading region aria-busy and let the real content announce when it arrives.

Accessibility

AA4.1.3Status Messages
  • Skeletons are decorative — mark the loading region with aria-busy=true and aria-hidden the placeholders.
  • Announce completion by swapping to real content (and clearing aria-busy).