Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Text

Pro

Skeleton Text for React

A loading placeholder that becomes its text: shimmering bars while it loads, then the words coming in one by one. For React with Base UI, when text should arrive in place of a skeleton without a jump.

Framework

Skeleton Text stands in for text that's still loading: a few bars, a line each, with a soft band of light crossing them. When loading turns false the bars fade and the text comes in a word at a time, in the same place, so the moment it arrives feels deliberate rather than a flash. The bars and the text share one cell, so the taller of the two holds the height and nothing below them jumps.

Use it for text fetched after the page shows: a summary, a profile's bio, an assistant's answer, a card's title. For a placeholder with no text to become, such as an image or an avatar, use Skeleton; to show that someone is writing a reply, Typing Indicator Text. It's CSS only: loading sets a data attribute, and keyframe animations the install adds to your stylesheet draw the shimmer and bring the words in, with no script and no animation library. With reduced motion the bars hold still and the text simply appears.

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Usage

import { SkeletonTextEffect } from "@/components/ui/skeleton-text";
<SkeletonTextEffect loading={isLoading} text={summary ?? ""} />

Demos

Card

lines is how many bars stand in for the text, 3 by default: one for a title, two or three for a paragraph. label is what screen readers hear while it loads, and stagger the time between one word and the next. Reloading turns loading back on, and the bars return.

Preview width

Accessibility

While it loads, the text has aria-busy="true" and screen readers hear label, "Loading" by default; once loaded, they hear the text once, from a visually hidden copy, never the words one by one. The bars are hidden from them. The shimmer is a slow band of light, never a flash, and with reduced motion the bars hold still and the text appears without moving.

FAQ

Why is it called SkeletonTextEffect?

Because Skeleton already has a SkeletonText on some targets, and the two can be installed side by side. The file is skeleton-text, the component SkeletonTextEffect, and its data-slot is skeleton-text-effect, so neither clashes.

What do I pass as text while it loads?

Whatever you have, often nothing yet: text={summary ?? ""}. The bars stand in for it, and when loading turns false the text comes in. If you already know the text, it holds its own height under the bars from the start.

Will the page jump when the text arrives?

Not if the bars are as tall as the text: the bars and the text share one cell, and the taller sets its height. Set lines to the number of lines the text usually takes at that width.

Does it play again when it reloads?

Yes: set loading back to true and the bars return; set it to false and the words come in again.

What if the text is ready when the page loads?

With loading left false, the words come in once as the page shows, then stay.

What happens with reduced motion?

The bars are there without the shimmer, and the text appears in their place without moving.

API Reference

SkeletonTextEffect

<span> data-slot="skeleton-text-effect"

PropType
textstring

The text it becomes. Its line breaks (\n) are kept.

label?string

What screen readers hear while it loads. @default "Loading".

Default
"Loading"
lines?number

How many bars stand in for the text while it loads. @default 3.

Default
3
loading?boolean

Whether the text is still loading: shimmering bars until it's false, then the text. @default false.

Default
false
stagger?number

The time between one word coming in and the next, in milliseconds. @default 30.

render?ReactElement | ((props: object, state: object) => ReactElement)

Replace the host element or compose it with another component.

Type
ReactElement | ((props: object, state: object) => ReactElement)
className?string

Merged with the part's classes.

AttributeType
data-state?string

"loading" when loading is true, otherwise "ready".

CSS variableType
--skeleton-text-staggerstring

The time between one word coming in and the next (30ms).

All 97 text effects