component — feedback
Skeleton
A pulsing placeholder for content that is still loading, styled with the quebi design system. Compose several to mirror the shape of the eventual content.
- loading
- placeholder
- shimmer
- pulse
- feedback
07 examples
Default
A single block placeholder. Set width and height with utility classes.
Soft
A fainter fill for nested or secondary placeholders.
Text lines
Stack a few skeletons of varying width to suggest a paragraph.
Avatar with lines
Mix a circle with text lines to mirror a list item or comment.
Repeated unit
A list's fallback is its unit, repeated — heading, description, box — so the stack is roughly the height the content will be and nothing below it jumps when the content lands. One bar for a whole list tells the reader nothing about how much is coming.
Code block
Lines of varying width and indentation, on the surface the code will land on. Widths come from a fixed list by index, never Math.random(): a prerendered page would otherwise bake one set of widths into its HTML and roll different ones at hydration.
Card
A full card placeholder built from several skeletons.
source
skeleton.tsxCopy this into your project. Resolve its dependencies from the registryDependencies in the component's API entry.
import { cn } from "@/lib/utils"
/**
* Skeleton — quebi design system
*
* A pulsing placeholder for content that is still loading. Compose several
* skeletons to mirror the shape of the eventual content.
*
* The fill is `raised` — the ground of a hovered row, an ink tint in both
* themes — and the bar is square, like the content it stands in for. `soft`
* drops it further for nested or secondary placeholders.
*
* A Skeleton *is* the component — there is no text, border or glyph carrying
* the shape if the fill fails — which is why the pulse is `quebi-pulse` rather
* than Tailwind's `animate-pulse`: that one troughs at 0.5 opacity, halving a
* fill this faint every two seconds.
*/
export interface SkeletonProps extends React.ComponentProps<"div"> {
/** Use a fainter fill for nested or secondary placeholders. */
soft?: boolean
}
export function Skeleton({ ref, soft = false, className, ...props }: SkeletonProps) {
return (
<div
data-slot="skeleton"
ref={ref}
className={cn(
"shrink-0 quebi-pulse",
soft ? "bg-quebi-raised/60" : "bg-quebi-raised",
className,
)}
{...props}
/>
)
}