All Taste components
Data display
Skeleton loading
Grey placeholders in the shape of the content, shown while it loads.
card · list rows · shimmer
Loading
import { cn } from "@/lib/utils";
/** Shimmering placeholder; add the shimmer keyframes below to your globals.css. */
export function Skeleton({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
return (
<div
aria-hidden
className={cn(
"rounded-sm bg-[linear-gradient(90deg,var(--tst-surface-2)_0%,var(--tst-surface)_50%,var(--tst-surface-2)_100%)] bg-[length:200%_100%] animate-[shimmer_1.4s_linear_infinite] motion-reduce:animate-none",
className,
)}
{...props}
/>
);
}
// globals.css: @keyframes shimmer { to { background-position: -200% 0; } }
export function CardSkeleton() {
return (
<div role="status" aria-busy="true" className="grid gap-3 rounded-lg border border-border bg-bg p-4">
<span className="sr-only">Loading</span>
<Skeleton className="h-28 rounded" />
<Skeleton className="h-3.5 w-[70%]" />
<Skeleton className="h-2.5 w-[95%]" />
<Skeleton className="h-2.5 w-[55%]" />
<div className="mt-1 flex justify-between">
<Skeleton className="h-[22px] w-16 rounded-full" />
<Skeleton className="h-[30px] w-20 rounded" />
</div>
</div>
);
}
export function ListSkeleton({ rows = 4 }: { rows?: number }) {
return (
<div role="status" aria-busy="true" className="grid gap-4">
<span className="sr-only">Loading</span>
{Array.from({ length: rows }, (_, i) => (
<div key={i} className="flex items-center gap-3">
<Skeleton className="size-8 shrink-0 rounded-full" />
<div className="grid flex-1 gap-1.5">
<Skeleton className="h-2.5 w-3/4" />
<Skeleton className="h-2 w-2/5" />
</div>
</div>
))}
</div>
);
}
The code uses the Taste Tailwind preset. Make yours on the Taste page with Export my system.