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,
  Button,
  Sheet,
  Skeleton,
  Typography,
} from 'tailwind-joy/components';
export function SkeletonLoading() {
  const [loading, setLoading] = useState(true);
  return (
    <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>
  );
}
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,
  Button,
  Sheet,
  Skeleton,
  Typography,
} from 'tailwind-joy/components';
export function SkeletonAnimation() {
  return (
    <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>
  );
}
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,
  Stack,
  Switch,
  Typography,
} from 'tailwind-joy/components';
export function SkeletonInlineWithTypography() {
  const [loading, setLoading] = useState(true);
  return (
    <Stack spacing="16px" useFlexGap className="max-w-prose">
      <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>
    </Stack>
  );
}
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.