Skeleton
Available from version 0.5.0
Skeletons are preview placeholders for components that haven't loaded yet, reducing load-time frustration.
Basics
import { Skeleton } from 'tailwind-joy/components';
Customization
Loading
The Skeleton has the loading
prop set to true
by default.
Set it to false
to hide the Skeleton component.
If the Skeleton has children, they will be rendered instead.
Lorem ipsum is placeholder text commonly used in the graphic, print, and publishing industries.
import { useState } from 'react';
import {
AspectRatio,
Box,
Button,
Sheet,
Skeleton,
Typography,
} from 'tailwind-joy/components';
export function SkeletonLoading() {
const [loading, setLoading] = useState(true);
return (
<Box className="w-full space-y-4">
<Sheet
variant="outlined"
className="mx-auto flex w-full max-w-[343px] flex-col gap-y-3 rounded-lg p-4"
>
<AspectRatio ratio="21/9">
<Skeleton loading={loading} variant="overlay">
<img
alt=""
src={
loading
? 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='
: 'https://images.unsplash.com/photo-1686548812883-9d3777f4c137?h=400&fit=crop&auto=format&dpr=2'
}
/>
</Skeleton>
</AspectRatio>
<Typography>
<Skeleton loading={loading}>
{loading
? 'Lorem ipsum is placeholder text commonly used in the graphic, print, and publishing industries.'
: 'An aerial view of a road in the middle of a forest. This image was uploaded by Dian Yu on Unsplash.'}
</Skeleton>
</Typography>
<Button onClick={() => setLoading(!loading)}>
{loading ? 'Stop' : 'Start'} loading
</Button>
</Sheet>
</Box>
);
}
Animation
Use the animation
prop to control how the Skeleton component animates.
The animation
prop value can be one of the following:
pulse
(default): The background of the Skeleton fades in and out.wave
: A wave animation flowing from left to right.false
: Disable the animation entirely.
The demo below shows the wave animation:
Lorem ipsum is placeholder text commonly used in the graphic, print, and publishing industries.
import {
AspectRatio,
Box,
Button,
Sheet,
Skeleton,
Typography,
} from 'tailwind-joy/components';
export function SkeletonAnimation() {
return (
<Box className="w-full space-y-4">
<Sheet
variant="outlined"
className="mx-auto flex w-full max-w-[343px] flex-col gap-y-3 rounded-lg p-4"
>
<AspectRatio ratio="21/9">
<Skeleton animation="wave" variant="overlay">
<img
alt=""
src="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs="
/>
</Skeleton>
</AspectRatio>
<Typography className="overflow-hidden">
<Skeleton animation="wave">
Lorem ipsum is placeholder text commonly used in the graphic, print,
and publishing industries.
</Skeleton>
</Typography>
<Button>
Read more
<Skeleton animation="wave" />
</Button>
</Sheet>
</Box>
);
}
Inline with Typography
Insert the Skeleton between the Typography component and the text to display placeholder lines.
A heading
HISTORY, PURPOSE AND USAGELorem ipsum is placeholder text commonly used in the graphic, print, and publishing industries for previewing layouts and visual mockups.
import { useState } from 'react';
import { Box, Skeleton, Switch, Typography } from 'tailwind-joy/components';
export function SkeletonInlineWithTypography() {
const [loading, setLoading] = useState(true);
return (
<Box className="w-full max-w-prose space-y-4">
<Box className="m-auto">
<Typography
level="h1"
className="relative overflow-hidden text-[1.25rem]"
>
<Skeleton loading={loading}>A heading</Skeleton>
</Typography>
<Typography
level="body-xs"
className="relative mb-4 mt-2 overflow-hidden"
>
<Skeleton loading={loading}>HISTORY, PURPOSE AND USAGE</Skeleton>
</Typography>
<Typography className="relative overflow-hidden">
<Skeleton loading={loading}>
<i>Lorem ipsum</i> is placeholder text commonly used in the graphic,
print, and publishing industries for previewing layouts and visual
mockups.
</Skeleton>
</Typography>
</Box>
<Box className="flex">
<label className="inline-flex items-center gap-2 text-[0.875rem] leading-[1.42858]">
<span className="inline-flex">
<Switch
size="sm"
checked={loading}
onChange={(event) => setLoading(event.target.checked)}
/>
</span>
<span className="text-joy-neutral-800 dark:text-joy-neutral-100 font-medium">
Loading
</span>
</label>
</Box>
</Box>
);
}
Geometry
To build a specific Skeleton shape, use the variant
prop and choose between circular
or rectangular
.
And to have it on a specific dimension, use the width
and height
props.
import { Box, Skeleton } from 'tailwind-joy/components';
export function SkeletonGeometry() {
return (
<div>
<Box className="m-auto flex items-center gap-4">
<Skeleton variant="circular" width={48} height={48} />
<div className="space-y-2">
<Skeleton variant="rectangular" width={200} height="1em" />
<Skeleton variant="rectangular" width={140} height="1em" />
</div>
</Box>
</div>
);
}
Text block
Use the variant="text"
and level
props to create a block of skeleton text that follows the theme's typography styles.
The level
prop value can be a theme's typography-related token.
The result of the skeleton text will have the same height as the text of the level
prop.
h1 Typeface
h2 Typeface
body-md Typeface
body-sm Typeface
body-xs Typefaceimport { Box, Skeleton, Typography } from 'tailwind-joy/components';
export function SkeletonTextBlock() {
return (
<Box className="grid max-w-[360px] grid-cols-[100px_1fr] gap-2">
<Skeleton variant="text" level="h1" />
<Typography level="h1">h1 Typeface</Typography>
<Skeleton variant="text" level="h2" />
<Typography level="h2">h2 Typeface</Typography>
<Skeleton variant="text" />
<Typography>body-md Typeface</Typography>
<Skeleton variant="text" level="body-sm" />
<Typography level="body-sm">body-sm Typeface</Typography>
<Skeleton variant="text" level="body-xs" />
<Typography level="body-xs">body-xs Typeface</Typography>
</Box>
);
}
Anatomy
The Skeleton component is composed of a single root <span>
element that wraps around its contents:
<div class="tj-skeleton-root ...">
<!-- Skeleton contents -->
</div>
API
See the documentation below for a complete reference to all of the props available to the components mentioned here.