Light

Skeleton

Use to show a placeholder while content is loading.

Spec · from metadata

When to use

  • Showing content placeholders while data is loading
  • Skeleton screens that mirror the layout of the final content
  • Replacing individual elements (text lines, avatars, cards) during async fetches

When not to use

  • For determinate progress — use Progress instead
  • For a full-page loading spinner — use a spinner/loader pattern instead
  • For empty states (no data, not loading) — use an empty state illustration instead

Anti-patterns

Avoid<Skeleton />
Prefer<Skeleton className="h-4 w-full" />

Skeleton has no default dimensions — it will be invisible without explicit height and width

Avoid<Skeleton className="h-12 w-12" /> <!-- for avatar -->
Prefer<Skeleton className="h-12 w-12 rounded-full" />

Use rounded-full for circular skeleton placeholders like avatars

Accessibility

  • Screen readerSkeleton is decorative; use aria-busy='true' on the parent container that is loading, and aria-live='polite' to announce when content loads

Token bindings

TokenCategoryUsage
bg-accentcolorSkeleton block background color
rounded-mdradiusDefault border radius
animate-pulsemotionPulsing opacity animation

Import

import { Skeleton } from "@timelycare/helix-ui"

Props

interface SkeletonProps {
  className?: string
}

Structure

ElementTailwind
Basebg-accent animate-pulse
Lineh-4 rounded-md bg-accent
Circle (avatar)size-10 rounded-full bg-accent
Square (image)aspect-square rounded-md bg-accent
Line gapgap-2 (8px)

Shapes

ShapeUse ForTailwind
LineText placeholdersh-4 w-[width] rounded-md bg-accent
CircleAvatar, icon placeholderssize-10 rounded-full bg-accent
SquareImage placeholdersaspect-square w-full rounded-md bg-accent

Common Patterns

Avatar with Text

<div className="flex items-center gap-4">
  <Skeleton className="size-10 rounded-full" />
  <div className="flex flex-col gap-2">
    <Skeleton className="h-4 w-[150px]" />
    <Skeleton className="h-4 w-[100px]" />
  </div>
</div>

Card Placeholder

<div className="flex flex-col gap-4 p-4">
  <div className="flex flex-col gap-2">
    <Skeleton className="h-4 w-full" />
    <Skeleton className="h-4 w-full" />
  </div>
  <Skeleton className="aspect-square w-full rounded-md" />
</div>

Text Lines

<div className="flex flex-col gap-2">
  <Skeleton className="h-4 w-[222px]" />
  <Skeleton className="h-4 w-[167px]" />
</div>

Table Row

<div className="flex items-center gap-4">
  <Skeleton className="h-4 w-[80px]" />
  <Skeleton className="h-4 w-[120px]" />
  <Skeleton className="h-4 w-[100px]" />
</div>

Sizing Guide

Content TypeWidth
Short labelw-[80px] - w-[100px]
Medium textw-[150px] - w-[200px]
Long textw-[250px] or w-full
Titlew-3/4 or w-[200px]
Descriptionw-full

Element Sizing Quick Reference

ElementHeightWidth
Titleh-6w-[200px] or contextual
Body texth-4w-full or w-[250px]
Avatarh-10 w-10 rounded-full
Buttonh-9w-[100px]
Checkboxh-4 w-4

Animation

The skeleton uses animate-pulse by default. This creates a subtle fade in/out effect.

// Already included in base component
<Skeleton className="animate-pulse ..." />

Accessibility

  • Purely presentational loading placeholder
  • Add aria-hidden="true" to skeleton containers
  • Use aria-busy="true" on the parent region that is loading
  • Screen reader announcements should use live regions, not skeletons
  • No keyboard interaction

Gotchas

ProblemSolution
No animationEnsure animate-pulse is applied
Wrong colorUse bg-accent (not bg-muted)
Lines too tallStandard height is h-4 (16px)
Varying widthsUse different widths per line for natural look
AccessibilityAdd aria-hidden="true" to skeleton containers

See Also

  • Related Components: Progress (determinate loading indicator), Spinner (inline loading indicator)

Last updated: February 9, 2026