Skip to content
Twilight React Playground
ثيم رائدaren

Skeleton building blocks

componentBeginnerserverbrowserlive demo

The pieces the page skeletons are made of: a pulsing bar, a breadcrumb row, a product card and a product grid.

import { SkeletonPulse, BreadcrumbSkeleton, ProductCardSkeleton, ProductGridSkeleton } from '@salla.sa/twilight-theme-engine/skeleton';

In plain words

When no ready-made page skeleton matches your page, build one from these parts. SkeletonPulse is a single grey, gently pulsing shape that you size yourself; the others are a breadcrumb row, one product card and a grid of product cards.

Signature

const SkeletonPulse: MemoExoticComponent<(props: {
  className?: string;
  circle?: boolean;          // rounded-full instead of rounded-md
  style?: CSSProperties;
}) => JSX.Element>

function BreadcrumbSkeleton(props?: { className?: string }): JSX.Element
function ProductCardSkeleton(props?: { className?: string }): JSX.Element
function ProductGridSkeleton(props?: { className?: string; count?: number }): JSX.Element  // count: 6

Try it live

A custom loading placeholder composed from the four skeleton building blocks, sized with inline styles.Try this: turn on the avatar, then change the grid count: ProductGridSkeleton always uses 4 columns.
Storefront canvas · ar · RTL
Controls
BreadcrumbSkeleton
SkeletonPulse circle
ProductGridSkeleton only. Default 6.
What a theme writes
import { memo } from 'react';
import { BreadcrumbSkeleton, ProductGridSkeleton, SkeletonPulse } from '@salla.sa/twilight-theme-engine/skeleton';

export const MyPageSkeleton = memo(function MyPageSkeleton() {
  return (
    <div className="container">
      <BreadcrumbSkeleton />
      <div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 16 }}>
        <SkeletonPulse style={{ width: 240, height: 24 }} />
      </div>
      <ProductGridSkeleton count={4} />
    </div>
  );
});

Example

app/components/LookbookSkeleton.tsx
import { memo } from 'react';
import {
  BreadcrumbSkeleton,
  ProductGridSkeleton,
  SkeletonPulse,
} from '@salla.sa/twilight-theme-engine/skeleton';

export const LookbookSkeleton = memo(function LookbookSkeleton() {
  return (
    <div className="container">
      <BreadcrumbSkeleton />
      <SkeletonPulse className="mb-6 h-8 w-1/3" />
      <ProductGridSkeleton count={8} />
    </div>
  );
});

How it behaves

  • SkeletonPulse renders one <div className="s-skeleton-pulse rounded-md"> (rounded-full with circle) with your className and style. Salla's Tailwind plugin styles s-skeleton-pulse as animate-pulse bg-gray-200. The other skeletons are built from it.

  • BreadcrumbSkeleton is three pulses in .s-skeleton-breadcrumb. ProductCardSkeleton uses the real product card classes (s-product-card …), so it takes a card's place in a product grid. ProductGridSkeleton renders count card skeletons (6 by default) in a 4-column grid.

  • Keep a custom skeleton a memo component with no hooks and no data, so it can never wait for anything itself.

  • The components package has more skeletons (menus, sliders, forms…); the engine re-exports only these four and the page skeletons.

  • All four are also exported from @salla.sa/twilight-theme-engine/components/common.

Gotchas

  • A SkeletonPulse has no size of its own. Without a height from className or style it is a zero-height div, and nothing shows.

  • ProductGridSkeleton always uses the 4-column grid, whatever count is. For another column count, lay out ProductCardSkeletons in a grid of your own.

Related

Source and docs