Skeleton
Placeholder shapes that mimic content while it loads — text lines, rectangles, and circles with pulse or wave animation.
Marked aria-hidden so screen readers skip placeholders; pair with an aria-live region to announce when real content arrives.
Preview
tsx
import { Skeleton } from '@arshad-shah/cynosure-react';
export default function Example() {
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem', width: 240 }}>
<Skeleton width={240} height={12} />
<Skeleton width={200} height={12} />
<Skeleton width={160} height={12} />
</div>
);
}
Variants
Section titled “Variants”Three shape variants are available: text (default — line height-aware), rect (sharper corners for media tiles), and circle (avatars and icon placeholders).
Preview
tsx
import { Skeleton } from '@arshad-shah/cynosure-react';
export default function Example() {
return (
<div style={{ display: 'flex', gap: '1.25rem', alignItems: 'center' }}>
<Skeleton variant="circle" width={48} height={48} />
<Skeleton variant="rect" width={120} height={72} />
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem' }}>
<Skeleton variant="text" width={200} height={12} />
<Skeleton variant="text" width={160} height={12} />
</div>
</div>
);
}
Animation
Section titled “Animation”Switch animation between "pulse" (default), "wave", and "none". The wave variant honours prefers-reduced-motion and falls back to a static state.
Preview
tsx
import { Skeleton } from '@arshad-shah/cynosure-react';
export default function Example() {
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: '1rem', width: 240 }}>
<div>
<p
style={{
margin: '0 0 0.25rem',
fontSize: '0.75rem',
color: 'var(--cynosure-color-fg-muted)',
}}
>
pulse
</p>
<Skeleton width={240} height={12} animation="pulse" />
</div>
<div>
<p
style={{
margin: '0 0 0.25rem',
fontSize: '0.75rem',
color: 'var(--cynosure-color-fg-muted)',
}}
>
wave
</p>
<Skeleton width={240} height={12} animation="wave" />
</div>
<div>
<p
style={{
margin: '0 0 0.25rem',
fontSize: '0.75rem',
color: 'var(--cynosure-color-fg-muted)',
}}
>
none
</p>
<Skeleton width={240} height={12} animation="none" />
</div>
</div>
);
}
Card placeholder
Section titled “Card placeholder”Compose multiple skeletons into a card-shaped placeholder while a fetch is in flight.
Preview
tsx
import { Skeleton } from '@arshad-shah/cynosure-react';
export default function Example() {
return (
<div
style={{
width: 280,
padding: '1rem',
border: '1px solid var(--cynosure-color-border)',
borderRadius: 'var(--cynosure-radius-lg)',
display: 'flex',
flexDirection: 'column',
gap: '0.75rem',
}}
>
<Skeleton variant="rect" width="100%" aspectRatio="16 / 9" />
<div style={{ display: 'flex', gap: '0.75rem', alignItems: 'center' }}>
<Skeleton variant="circle" width={32} height={32} />
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.375rem', flex: 1 }}>
<Skeleton width="60%" height={10} />
<Skeleton width="40%" height={10} />
</div>
</div>
<Skeleton width="100%" height={12} />
<Skeleton width="80%" height={12} />
</div>
);
}
PropTypeDefaultDescription
variant
"text"|"rect"|"circle"
text
Visual shape: `text` is a short rounded line, `rect` is a flexible
rectangle, `circle` paints a perfectly round shape (pair with equal
`width` and `height`).
animation
"pulse"|"wave"|"none"
pulse
Loading animation. `pulse` fades opacity in/out, `wave` sweeps a
highlight across, `none` disables motion.
width
string|number
—
Explicit width (number is converted to `px`).
height
string|number
—
Explicit height (number is converted to `px`).
aspectRatio
string|number
—
CSS `aspect-ratio` for proportional placeholders (e.g. `"16 / 9"`).
Accessibility
Section titled “Accessibility”aria-hidden="true"by default so the placeholder is not announced.- Honours
prefers-reduced-motion— falls back to a static state when animations are disabled. - Pair with an
aria-live="polite"region (or a status message) that announces when real content arrives. - Use enough placeholder rows to match the inbound content’s rough shape — sudden layout shifts hurt low-vision users most.
- Skeletons carry
data-varianton the host element so design tokens can theme each shape differently.
Recipes
Section titled “Recipes”- Use
variant="text"for line placeholders that inherit the surrounding type scale; pass a smallerwidthon the last line for natural ragged-edge text. - Use
variant="circle"with equalwidthandheightfor avatar placeholders. - Pass
aspectRatio(e.g."16 / 9") instead ofheightfor responsive media tiles. - Set
animation="none"inside infinite scrollers — many simultaneous wave animations get distracting fast.