|Kit

Skeleton

Loading placeholder — a fixed rectangular/circular shape, or a wrap mode that sizes itself to real children and reveals them once loaded.

Skeleton is a loading placeholder. Standalone, it's a fixed rectangular or circular shape; wrapped around real content, it sizes itself to that content's own box and reveals it once loading finishes. DataTable's own skeleton rows and cards render through this component internally.

import { Skeleton } from '@42/ui-react/skeleton';

<Skeleton />
<Skeleton shape="circular" width={40} height={40} />

<Skeleton loading={isLoading}>
  <UserAvatar user={user} />
</Skeleton>

Playground

Component

SpinnerLoading preview

Props

Code

<Component shape="rectangular" size="md" />

Full prop browser

Shapes

Two shapes: rectangular (the default — fills its container's width) and circular (a fixed-diameter dot).

Code

<Skeleton shape="rectangular" /><Skeleton shape="circular" />

Sizes

size steps through the kit's shared xsxl scale — the same steps DataTable's own density prop uses, so a skeleton bar matches whatever table density it stands in for. It's tuned for text-line bars (8–24px tall); for a bigger shape like an avatar circle, use width/height instead (see Recipes).

Code

<Skeleton size="xs" /><Skeleton size="sm" /><Skeleton size="md" /><Skeleton size="lg" /><Skeleton size="xl" />

Wrap mode

Pass children and Skeleton sizes a placeholder to match — no measurement, no ResizeObserver: the real content stays mounted (just made invisible) while loading, so it keeps contributing its own box to the wrapper the placeholder fills. Click below to see the same Skeleton instance swap live between the placeholder and the real content it's wrapping — "Reveal" flips loading to false, "Reset" flips it back.

Code

function Demo() {  const [loading, setLoading] = useState(true);  return (    <>      <Button size="sm" variant="light" color="gray" onClick={() => setLoading((v) => !v)}>        {loading ? 'Reveal' : 'Reset'}      </Button>      <Skeleton loading={loading}>        <span className="text-sm">Real content, revealed once loaded</span>      </Skeleton>    </>  );}

The overlay's shape/size still come from those props, same as standalone mode — only the placeholder's dimensions are inferred from the child, not its shape (a circular avatar's wrapper won't automatically become a circular placeholder; pass shape="circular" for that too).

The wrapper shrink-wraps to the content's own intrinsic size — content that itself stretches to fill its container (w-full, flex-1, an unconstrained block paragraph) won't get a full-width overlay from wrap mode alone. Add className="block w-full" in that case, or fall back to standalone mode with an explicit width.

Recipes

Skeleton has no layout logic of its own — complex, card-style loading states are built by composing plain shapes inside the kit's existing Card and Flex/Grid. This is exactly the pattern DataTable's stacked-card loading view uses internally.

Rectangle

Code

<Skeleton size="sm" /><Skeleton size="md" className="w-2/3" />

Circle

Code

<Skeleton shape="circular" width={40} height={40} />

Card stack — DataTable's own stacked skeleton pattern

Code

<Card padding="sm">  <Flex gap="sm" align="center">    <Skeleton shape="circular" width={40} height={40} />    <Flex direction="col" gap="xs" className="flex-1">      <Skeleton size="sm" className="w-1/3" />      <Skeleton size="xs" className="w-2/3" />    </Flex>  </Flex></Card>

API

Prop

Type

All other props are forwarded to the root <div>.

Accessibility

A standalone placeholder is aria-hidden — it's a visual stand-in with nothing for assistive tech to announce. In wrap mode, the wrapper carries aria-busy/data-loading while loading, and the real (still-mounted, invisible) content is hidden from assistive tech until it's revealed. The pulse animation respects prefers-reduced-motion (motion-reduce:animate-none) — an improvement DataTable's own pre-existing skeleton bars didn't have before adopting this component.

On this page