Skip to content
FeedbackGenerated from the public API

Skeleton

A placeholder that reserves the shape of what is loading.

@luc/ui

Examples

A placeholder that keeps the shape it reserved

Press the button: the same rows arrive where the placeholder was, and nothing on the card moves. That is the reason to reach for a skeleton instead of a spinner.

Every line is drawn at the height of the line it stands in for.

The three variants

`text` is a line, `block` is a surface, `circle` is a person or a mark.

text

block

circle

A list that reserves its rows

A table's placeholder is a grid, not a paragraph: the columns have to line up with the columns that are coming.

Shimmer, on and off

One shimmer per view is feedback; a dozen is noise. The static surface is the honest choice for everything else.

shimmer · the page's main wait

no shimmer · a quiet region

A page region, not a page

A region that is loading keeps its own frame: the panel, the heading and the chart body are all already there.

Usage

import { Skeleton, SkeletonText } from "@luc/ui";
<SkeletonText lines={3} />
<Skeleton variant="circle" className="size-9" />

A `block` reserves a surface, a `circle` an avatar, and text lines come from `SkeletonText`.

Package setup — peer requirements, the stylesheet and the provider — is on installation.

API

Read from the published TypeScript API, so a prop that is not listed here does not exist and a default that is listed is the one the compiler sees.

Two components: the placeholder itself (`variant` and `shimmer`) and `SkeletonText`, the multi-line helper that varies its line widths so a block reads as prose.

Exported symbols
ExportKindSignature
Skeleton2 documented props({ className, variant, shimmer, ...props }: SkeletonProps) => import("@types/react").JSX.Element
SkeletonText3 documented props({ lines, widths, className, ...props }: SkeletonTextProps) => import("@types/react").JSX.Element

Skeleton props

Type: SkeletonProps

Values the compiler reads from the declaration.

Skeleton props
PropTypeDefaultNotes
shimmer?boolean | undefined—Sweep a highlight across the placeholder. Default `true`.
variant?"circle" | "text" | "block" | undefined—`text` is a single line, `block` a surface, `circle` an avatar.

SkeletonText props

Type: SkeletonTextProps

Values the compiler reads from the declaration.

SkeletonText props
PropTypeDefaultNotes
lines?number | undefined—
shimmer?boolean | undefined—Sweep a highlight across the placeholder. Default `true`.
widths?string[] | undefined—Vary line widths so the block reads as prose, not a table.

Guidelines

Do

  • Reserve the shape of what is coming: the same number of lines, the same row height, the same avatar size.
  • Use `SkeletonText` for prose and hand-written widths for anything with a rhythm of its own.
  • Keep the placeholder in the loaded content's own layout, so nothing moves when the data lands.

Don't

  • Do not let a skeleton be taller or shorter than the content it replaces — that is a layout shift with extra steps.
  • Do not shimmer a dozen placeholders: the page's one main wait is worth the movement, the rest is noise.
  • Do not use a skeleton for an action's wait inside a button; that is a spinner.

Accessibility

A skeleton is `aria-hidden` on purpose: it is a picture of content, not content. That makes the live relationship the caller's job — `aria-busy` on the loading region is what tells a screen reader that what it can read there is not final — and the shimmer is `motion-safe`, so a reader who asked for reduced motion gets a static placeholder with the same geometry.

Family

Feedback

What the product says when something happened, is happening, or did not.

10 documented entries in this family. Open the family index

Luc UI v1.0Skeletondark theme