Skip to contentSkip to navigationSkip to topbar
Paste assistant Assistant
Figma
Star

Skeleton Loader

Version 6.1.1GithubStorybookPeer review pending

A Skeleton Loader is a visual placeholder that gives users a hint of what type of information will be loaded on a page.

Component preview theme
<SkeletonLoader />

Guidelines

Guidelines page anchor

About Skeleton Loader

About Skeleton Loader page anchor

The Skeleton Loader displays a placeholder representing the page's content before the page is ready to display. This component is used to improve perceived performance(link takes you to an external page). This tends to improve user experience by reducing load time frustration and making the page feel more responsive.

This loader is an alternative to the Spinner component. Rather than showing an abstract spinner, it frames the content of what is to come which creates anticipation.

The component is designed to be used in place of the content being loaded. For example:

Component preview theme
const SkeletonLoaderComposition = () => {
const [loaded] = React.useState(false);
return (
<>
{loaded ?
<Text as="span">Single line of text</Text> :
<SkeletonLoader width="100px" />
}
</>
);
};
render(
<SkeletonLoaderComposition />
)
  • The animation can be disabled by enabling the prefers-reduced-motion setting at the OS level.
  • Skeleton Loader has the aria-busy attribute set to true by default. This is to indicate that the content is loading.

The default Skeleton Loader can be used to represent a line of text. It uses the sizeIcon20 token for the height, and borderRadius20 for the border-radius. The width will be 100% unless a different width is specified.

Component preview theme
<SkeletonLoader />

Changing the Skeleton Loader height

Changing the Skeleton Loader height page anchor

Use the height prop to change the height of the Skeleton Loader. The height can be any valid height unit, such as px, rem, or %. It can also be one of the Paste size tokens.

Component preview theme
<SkeletonLoader height="150px" />
Component preview theme
const SkeletonLoaderText = () => {
const [loaded, setLoaded] = React.useState(false);
return (
<>
{loaded ? <Text as="span">Single line of text</Text> : <SkeletonLoader width="100px" />}
<Box marginTop="space60">
<Stack orientation="horizontal" spacing="space60">
<Button variant="secondary" size="small" onClick={() => setLoaded(true)}>
Load content
</Button>
<Button variant="secondary" size="small" onClick={() => setLoaded(false)}>
Reset
</Button>
</Stack>
</Box>
</>
);
};
render(
<SkeletonLoaderText />
)

In order to simulate a paragraph's line spacing, you can use the Stack component.

Component preview theme
const SkeletonLoaderParagraph = () => {
const [loaded, setLoaded] = React.useState(false);
return (
<>
{loaded ? (
<Box width="500px">
<Paragraph>
Impossible is just a big word thrown around by small men who find it easier to live in the world they’ve been given than to explore the power they have to change it. Impossible is not a fact. It’s an opinion. Impossible is not a declaration. It's a dare. Impossible is potential. Impossible is temporary. Impossible is nothing.
</Paragraph>
</Box>
) : (
<Box width="500px">
<Stack orientation="vertical" spacing="space20">
<SkeletonLoader />
<SkeletonLoader />
<SkeletonLoader />
<SkeletonLoader />
<SkeletonLoader width="80px" />
</Stack>
</Box>
)}
<Box marginTop="space60">
<Stack orientation="horizontal" spacing="space60">
<Button variant="secondary" size="small" onClick={() => setLoaded(true)}>
Load content
</Button>
<Button variant="secondary" size="small" onClick={() => setLoaded(false)}>
Reset
</Button>
</Stack>
</Box>
</>
);
};
render(
<SkeletonLoaderParagraph />
)
Component preview theme
const SkeletonLoaderHeading = () => {
const [loaded, setLoaded] = React.useState(false);
return (
<>
{loaded ? (
<Stack orientation="vertical" spacing="space60">
<Heading as="h1" variant="heading10">
Heading one
</Heading>
<Heading as="h2" variant="heading20">
Heading two
</Heading>
<Heading as="h3" variant="heading30">
Heading three
</Heading>
<Heading as="h4" variant="heading40">
Heading four
</Heading>
<Heading as="h5" variant="heading50">
Heading five
</Heading>
<Heading as="h6" variant="heading60">
Heading six
</Heading>
</Stack>
) : (
<Stack orientation="vertical" spacing="space60">
<SkeletonLoader height="44px" width="100px" />
<SkeletonLoader height="32px" width="100px" />
<SkeletonLoader height="28px" width="100px" />
<SkeletonLoader height="24px" width="100px" />
<SkeletonLoader height="20px" width="100px" />
<SkeletonLoader height="20px" width="100px" />
</Stack>
)}
<Box marginTop="space60">
<Stack orientation="horizontal" spacing="space60">
<Button variant="secondary" size="small" onClick={() => setLoaded(true)}>
Load content
</Button>
<Button variant="secondary" size="small" onClick={() => setLoaded(false)}>
Reset
</Button>
</Stack>
</Box>
</>
);
};
render(
<SkeletonLoaderHeading />
)
Component preview theme
const SkeletonLoaderButtons = () => {
const [loaded, setLoaded] = React.useState(false);
return (
<>
{loaded ? (
<Stack orientation="horizontal" spacing="space40">
<Button variant="primary">Button one</Button>
<Button variant="secondary">Button two</Button>
<Button variant="secondary">Button three</Button>
</Stack>
) : (
<Stack orientation="horizontal" spacing="space40">
<SkeletonLoader width="98px" height="36px" />
<SkeletonLoader width="98px" height="36px" />
<SkeletonLoader width="108px" height="36px" />
</Stack>
)}
<Box marginTop="space60">
<Stack orientation="horizontal" spacing="space60">
<Button variant="secondary" size="small" onClick={() => setLoaded(true)}>
Load content
</Button>
<Button variant="secondary" size="small" onClick={() => setLoaded(false)}>
Reset
</Button>
</Stack>
</Box>
</>
);
};
render(
<SkeletonLoaderButtons />
)
Component preview theme
const SkeletonLoaderAvatar = () => {
const [loaded, setLoaded] = React.useState(false);
return (
<>
{loaded ? (
<Avatar size="sizeIcon70" name="Paste Engineer" />
) : (
<SkeletonLoader borderRadius="borderRadiusCircle" size="sizeIcon70" />
)}
<Box marginTop="space60">
<Stack orientation="horizontal" spacing="space60">
<Button variant="secondary" size="small" onClick={() => setLoaded(true)}>
Load content
</Button>
<Button variant="secondary" size="small" onClick={() => setLoaded(false)}>
Reset
</Button>
</Stack>
</Box>
</>
);
};
render(
<SkeletonLoaderAvatar />
)
Component preview theme
const SkeletonLoaderIcon = () => {
const [loaded, setLoaded] = React.useState(false);
return (
<>
{loaded ? <CalendarIcon decorative={false} title="Calendar icon" /> : <SkeletonLoader size="sizeIcon30" />}
<Box marginTop="space60">
<Stack orientation="horizontal" spacing="space60">
<Button variant="secondary" size="small" onClick={() => setLoaded(true)}>
Load content
</Button>
<Button variant="secondary" size="small" onClick={() => setLoaded(false)}>
Reset
</Button>
</Stack>
</Box>
</>
);
};
render(
<SkeletonLoaderIcon />
)
Component preview theme
const SkeletonLoaderCard = () => {
const [loaded, setLoaded] = React.useState(false);
return (
<>
{loaded ? (
<Box width="500px">
<Card>
<Heading as="h1" variant="heading10">
Impossible
</Heading>
<Paragraph>Impossible is just a big word thrown around by small men who find it easier to live in the world they’ve been given than to explore the power they have to change it. Impossible is not a fact. It’s an opinion. Impossible is not a declaration. It's a dare. Impossible is potential. Impossible is temporary. Impossible is nothing.</Paragraph>
</Card>
</Box>
) : (
<Box width="500px">
<Card>
<Box marginBottom="space80">
<SkeletonLoader height="44px" width="100px" />
</Box>
<Stack orientation="vertical" spacing="space20">
<SkeletonLoader />
<SkeletonLoader />
<SkeletonLoader />
<SkeletonLoader />
</Stack>
<Box marginTop="space20" marginBottom="space80">
<SkeletonLoader width="200px" />
</Box>
</Card>
</Box>
)}
<Box marginTop="space60">
<Stack orientation="horizontal" spacing="space60">
<Button variant="secondary" size="small" onClick={() => setLoaded(true)}>
Load content
</Button>
<Button variant="secondary" size="small" onClick={() => setLoaded(false)}>
Reset
</Button>
</Stack>
</Box>
</>
);
};
render(
<SkeletonLoaderCard />
)
Component preview theme
const SkeletonLoaderTable = () => {
const [loaded, setLoaded] = React.useState(false);
return (
<>
<Table tableLayout="fixed">
<THead>
<Tr>
<Th width="300px">Contacts</Th>
<Th>Date Added</Th>
<Th>Last Opened</Th>
</Tr>
</THead>
<TBody>
<Tr>
<Td>{loaded ? <Text as="span">Adriana Lovelock</Text> : <SkeletonLoader width="50%" />}</Td>
<Td>{loaded ? <Text as="span">2020-09-17</Text> : <SkeletonLoader width="35%" />}</Td>
<Td>{loaded ? <Text as="span">2020-06-28</Text> : <SkeletonLoader width="35%" />}</Td>
</Tr>
<Tr>
<Td>{loaded ? <Text as="span">Adam Brown</Text> : <SkeletonLoader width="35%" />}</Td>
<Td>{loaded ? <Text as="span">2020-03-06</Text> : <SkeletonLoader width="35%" />}</Td>
<Td>{loaded ? <Text as="span">2020-08-17</Text> : <SkeletonLoader width="35%" />}</Td>
</Tr>
<Tr>
<Td>{loaded ? <Text as="span">Amanda Cutlack</Text> : <SkeletonLoader width="55%" />}</Td>
<Td>{loaded ? <Text as="span">2020-02-11</Text> : <SkeletonLoader width="35%" />}</Td>
<Td>{loaded ? <Text as="span">2020-12-27</Text> : <SkeletonLoader width="35%" />}</Td>
</Tr>
<Tr>
<Td>{loaded ? <Text as="span">John Daily</Text> : <SkeletonLoader width="30%" />}</Td>
<Td>{loaded ? <Text as="span">2020-04-92</Text> : <SkeletonLoader width="35%" />}</Td>
<Td>{loaded ? <Text as="span">2020-09-17</Text> : <SkeletonLoader width="35%" />}</Td>
</Tr>
</TBody>
</Table>
<Box marginTop="space60">
<Stack orientation="horizontal" spacing="space60">
<Button variant="secondary" size="small" onClick={() => setLoaded(true)}>
Load content
</Button>
<Button variant="secondary" size="small" onClick={() => setLoaded(false)}>
Reset
</Button>
</Stack>
</Box>
</>
);
};
render(
<SkeletonLoaderTable />
)