Skip to content

Skeleton

A placeholder in the shape of content that is still loading, so the layout doesn’t shift when it arrives. For waits longer than a few seconds, show a status message instead.

Code
demo.tsx
import {Heading, Skeleton, SkeletonText, Stack, Text} from '@earendil-works/elanor-react';

export default function SkeletonDemo() {
  return (
    <Stack gap="small" align="stretch" aria-busy>
      <Heading level={2} size={4}>
        <Skeleton>Workspace settings</Skeleton>
      </Heading>
      <Text>
        <SkeletonText lines={3} />
      </Text>
    </Stack>
  );
}

Usage

import {Skeleton, SkeletonText} from '@earendil-works/elanor-react';

<Skeleton loading={!user}>{user?.name ?? 'Placeholder name'}</Skeleton>;
<SkeletonText lines={3} />;

Skeleton covers its content in semantic.color.background.skeleton and pulses with semantic.transition.pulse. The content keeps its size but is hidden from screen readers and keyboard focus, so set aria-busy on the region that is loading. Skeleton renders a span; use render={<div />} around blocks.

Loading

loading switches between the placeholder and the content in the same element, without a layout shift.

Active projects
12
Across three teams
Code
loading.tsx
import {Button, Card, Skeleton, Stack} from '@earendil-works/elanor-react';
import {useState} from 'react';

export default function SkeletonLoading() {
  const [loading, setLoading] = useState(false);

  return (
    <Stack gap="medium">
      <Skeleton loading={loading} render={<div />}>
        <Card label="Active projects" value="12" description="Across three teams" />
      </Skeleton>
      <Button
        hierarchy="secondary"
        pending={loading}
        onClick={() => {
          setLoading(true);
          setTimeout(() => setLoading(false), 2000);
        }}
      >
        Refresh
      </Button>
    </Stack>
  );
}

Text

SkeletonText shows placeholder lines in the size of the surrounding text. Put it inside Text or Heading. In a Stack, use align="stretch" so the lines fill the width.

Code
text.tsx
import {SkeletonText, Text} from '@earendil-works/elanor-react';

export default function SkeletonTextExample() {
  return (
    <Text>
      <SkeletonText lines={4} />
    </Text>
  );
}

API

Skeleton

Covers content that is still loading with a placeholder of its size. Renders a span by default.

PropTypeDefaultDescription
loadingbooleantrueCovers the content with a placeholder of the same size.

Renders <span>. Also accepts its HTML attributes, ref, and render.

SkeletonText

Placeholder lines in the size of the surrounding text. Renders a span by default.

PropTypeDefaultDescription
linesnumber1Number of placeholder lines.

Renders <span>. Also accepts its HTML attributes, ref, and render.