Skip to content
Sign in
ConversationMessage skeletonMenu

Message skeleton

Placeholder for thread history while past messages load: alternating user bubbles and assistant paragraphs with varied line lengths. It renders through the real Message layout, so swapping in content causes no layout shift.

The skeleton holds the exact space of the messages that replace it, so nothing moves on swap.

Installation

$ pnpm dlx shadcn@latest add https://chatcn.dev/r/message-skeleton.json

Usage

tsx
import { MessageSkeleton } from "@/components/ui/chatcn/message-skeleton"

<ConversationContent>
  {history.isLoading ? <MessageSkeleton count={4} /> : messages.map(renderMessage)}
</ConversationContent>

Use it only for history, where the layout is known. A reply that has not started yet gets the Thinking label, never a skeleton paragraph. Bubbles, the 68ch measure, the avatar gutter and the 24 px prose line all come from Message and MessageContent themselves, so the skeleton and the content it becomes always agree.

Nothing shows for the first 200 ms (delay), so fast loads never flash. The space is reserved from the first frame, so the skeleton fading in moves nothing either.

Examples

Avatars and compact

Match the messages that will replace it: avatar reserves the gutter, startWith picks the first author, and layout="compact" matches the dense log style.

Reserve the avatar gutter, start with an assistant turn, or match the dense compact layout.

Static and RTL

Pulse off, as under reduced motion.

Props

PropTypeNotes
countnumberMessages to sketch. Defaults to 4
startWith"user" | "assistant"First author. Turns alternate. Defaults to user
avatarbooleanReserve the avatar gutter
layout"auto" | "compact"Match the Message layout
seednumberChanges the line lengths. Deterministic, so server and client agree
pulsebooleanSlow opacity pulse. Defaults to true, off under reduced motion
delaynumberMs before it shows. Defaults to 200
items{ from, lines?, chars? }[]The thread's shape: each message's role plus its line count or text length. With chars the skeleton measures the column and draws the exact lines and bubble width
labelstringAnnounced to screen readers. Defaults to "Loading earlier messages"

MessageSkeletonItem draws a single message with from, lines, avatar, layout and seed, for custom sequences.

Accessibility

  • The skeleton is one status region with a visually hidden label. The shapes themselves are hidden from assistive technology.
  • Remove it when history arrives; the messages that replace it are read normally.

Motion

  • No shimmer: the sweep is reserved for Thinking. Instead, a 2 s opacity pulse from 1 to 0.6 and back, on the kit's in-out curve.
  • Under reduced motion the pulse stops and the shapes stay still. The 150 ms fade in after the delay is kept, since it is opacity only.