骨架屏
New内容加载占位块,自带柔和微光扫过——形状完全由 className 决定,可组合出头像、文本条、图块。「减少动效」偏好下换成平缓的透明度脉冲。
TSXcomponents/previews/motion/skeleton.preview.tsx
import { Skeleton } from "@/components/motion/skeleton";
export function SkeletonPreview() {
return (
<div className="flex w-full max-w-md flex-col gap-8">
<div className="rounded-2xl border border-border bg-card p-5">
<div className="flex items-center gap-3">
<Skeleton className="size-12 shrink-0 rounded-full" />
<div className="flex flex-1 flex-col gap-2">
<Skeleton className="h-3 w-2/3" />
<Skeleton className="h-3 w-2/5" />
</div>
</div>
<Skeleton className="mt-5 h-32 w-full rounded-xl" />
<div className="mt-5 flex flex-col gap-2">
<Skeleton className="h-3 w-full" />
<Skeleton className="h-3 w-11/12" />
<Skeleton className="h-3 w-4/5" />
</div>
</div>
<div className="flex flex-col gap-3">
{["alpha", "beta", "gamma"].map((row) => (
<div key={row} className="flex items-center gap-3">
<Skeleton className="size-8 shrink-0 rounded-full" />
<Skeleton className="h-3 flex-1" />
<Skeleton className="h-3 w-12 shrink-0" shimmer={false} />
</div>
))}
</div>
</div>
);
}
TSXcomponents/motion/skeleton.tsx
// ui-lab-ten.vercel.app/components/motion/skeleton
// Ported from motion-anything (nexu-io, Apache-2.0), "Loading Shimmer" recipe.
import { cn } from "@/lib/utils";
export interface SkeletonProps {
/** Sweeps a soft highlight across the block. Defaults to true; set false for a flat static base color. */
shimmer?: boolean;
className?: string;
}
// A skeleton block: a muted base color with an optional CSS-only sweeping
// highlight. Size, radius and shape all come from className — this component
// only owns the fill and the sweep.
export function Skeleton({ shimmer = true, className }: SkeletonProps) {
return (
<>
{shimmer && (
<style>
{`
@keyframes uilab-skeleton-sweep { 100% { transform: translateX(100%); } }
.uilab-skeleton-shimmer::after {
content: "";
position: absolute;
inset: 0;
transform: translateX(-100%);
background: linear-gradient(90deg, transparent, color-mix(in oklch, var(--foreground) 14%, transparent), transparent);
animation: uilab-skeleton-sweep 1.4s ease-in-out infinite;
will-change: transform;
}
@media (prefers-reduced-motion: reduce) {
.uilab-skeleton-shimmer::after { animation: none; display: none; }
}
`}
</style>
)}
<div
aria-hidden="true"
className={cn(
"relative overflow-hidden rounded-md bg-muted",
shimmer && "uilab-skeleton-shimmer motion-reduce:animate-pulse",
className,
)}
/>
</>
);
}
安装
用 shadcn CLI 添加,或手动复制源码。
$ bunx --bun shadcn add @uilab/skeleton
Needs the theme tokens once. Already ran
shadcn init? You are set. Theme setupInstall dependencies
npm i clsx tailwind-mergeAdd util file
TSXlib/utils.ts
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
Copy the source code
TSXcomponents/motion/skeleton.tsx
// ui-lab-ten.vercel.app/components/motion/skeleton
// Ported from motion-anything (nexu-io, Apache-2.0), "Loading Shimmer" recipe.
import { cn } from "@/lib/utils";
export interface SkeletonProps {
/** Sweeps a soft highlight across the block. Defaults to true; set false for a flat static base color. */
shimmer?: boolean;
className?: string;
}
// A skeleton block: a muted base color with an optional CSS-only sweeping
// highlight. Size, radius and shape all come from className — this component
// only owns the fill and the sweep.
export function Skeleton({ shimmer = true, className }: SkeletonProps) {
return (
<>
{shimmer && (
<style>
{`
@keyframes uilab-skeleton-sweep { 100% { transform: translateX(100%); } }
.uilab-skeleton-shimmer::after {
content: "";
position: absolute;
inset: 0;
transform: translateX(-100%);
background: linear-gradient(90deg, transparent, color-mix(in oklch, var(--foreground) 14%, transparent), transparent);
animation: uilab-skeleton-sweep 1.4s ease-in-out infinite;
will-change: transform;
}
@media (prefers-reduced-motion: reduce) {
.uilab-skeleton-shimmer::after { animation: none; display: none; }
}
`}
</style>
)}
<div
aria-hidden="true"
className={cn(
"relative overflow-hidden rounded-md bg-muted",
shimmer && "uilab-skeleton-shimmer motion-reduce:animate-pulse",
className,
)}
/>
</>
);
}
API 参考
shimmer?booleanSweeps a soft highlight across the block. Defaults to true; set false for a flat static base color.
trueclassName?string—Keep in mind
Some components on this site are inspired by or recreated from existing work across the web. I'm not here to take credit; just to learn, experiment, and sometimes push things a bit further. If something looks familiar and I forgot to mention you, reach out and I'll fix that right away.