stream/ui
Browse the library

Comic Skeleton

A dashed, hand-inked loading block whose halftone dots drift like a printing press warming up.

betaComicSkeleton.tsx

Examples

Profile

comic-skeleton/basic.tsx
import { ComicSkeleton } from "@streamuilib/react";

export default function ComicSkeletonBasic() {
  return (
    <div aria-busy="true" aria-label="Loading profile" className="flex items-center gap-4">
      <ComicSkeleton className="size-14 rounded-full" />
      <div className="flex flex-col gap-2.5">
        <ComicSkeleton className="h-5 w-44" />
        <ComicSkeleton className="h-4 w-28" />
      </div>
    </div>
  );
}

In a comic panel

comic-skeleton/card.tsx
import { ComicSkeleton } from "@streamuilib/react";

export default function ComicSkeletonCard() {
  return (
    <div
      aria-busy="true"
      aria-label="Loading story"
      className="flex w-72 -rotate-1 flex-col gap-3 border-[3px] border-ink bg-paper-raised p-4 shadow-[5px_5px_0_var(--ink)]"
    >
      <ComicSkeleton className="h-32 w-full" />
      <ComicSkeleton className="h-5 w-3/4" />
      <ComicSkeleton className="h-4 w-full" />
      <ComicSkeleton className="h-4 w-1/2" />
    </div>
  );
}

Installation

bun add @streamuilib/react
Open in v0 (opens in a new tab)
usage.tsx
import { ComicSkeleton } from "@streamuilib/react";

<div aria-busy="true" aria-label="Loading">
  <ComicSkeleton className="h-4 w-40" />
</div>

API

PropTypeDefaultDescription
classNamestring—Size and shape it: h-4 w-40, size-12 rounded-full.
...propsComponentProps<"div">—Native div attributes.

Accessibility

  • Hidden from screen readers; put aria-busy and a label on the loading region instead.
  • The drifting dots stop for reduced motion.

Source

packages/react/src/ComicSkeleton.tsx
import type { ComponentProps } from "react";
import { cn } from "./cn";

/**
 * A comic-book loading placeholder: a dashed, hand-inked block of halftone
 * dots that drift across it like a printing press warming up. Size it with
 * classes (`h-4 w-40`, `size-12 rounded-full`). Hidden from screen readers;
 * mark the loading region with `aria-busy` and give it a label instead.
 */
export function ComicSkeleton({ className, ...props }: ComponentProps<"div">) {
  return (
    <div
      aria-hidden
      className={cn(
        "sui-comic-skeleton rounded-[10px_4px_8px_5px/5px_8px_4px_10px] border-[3px] border-dashed border-ink/35 bg-paper-sunken",
        className,
      )}
      {...props}
    />
  );
}