Placeholder representing loading content.
<div class="skeleton skeleton--text skeleton--animated" role="status" aria-label="Loading content">
<span class="skeleton__srtext">Loading content</span>
<div class="skeleton__avatar" aria-hidden="true"></div>
<div class="skeleton__lines" aria-hidden="true" style="--lines:3;">
<span class="skeleton__line"></span><span class="skeleton__line"></span><span class="skeleton__line"></span>
<span class="skeleton__line"></span><span class="skeleton__line"></span><span class="skeleton__line"></span>
</div>
</div>
<style>
.skeleton { display: flex; align-items: flex-start; gap: 12px; width: 260px; }
.skeleton__srtext { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
.skeleton__avatar { display: none; width: 44px; height: 44px; border-radius: 50%; background: #24143018; flex-shrink: 0; }
.skeleton--avatar .skeleton__avatar { display: block; }
.skeleton--card { flex-direction: column; }
.skeleton--card .skeleton__avatar { display: block; width: 100%; height: 120px; border-radius: 10px; }
.skeleton__lines { flex: 1; display: flex; flex-direction: column; gap: 8px; }
.skeleton__line { display: none; height: 10px; border-radius: 5px; background: #24143018; }
.skeleton__line:nth-child(1) { display: block; width: 100%; }
.skeleton__lines[style*="--lines:2"] .skeleton__line:nth-child(2),
.skeleton__lines[style*="--lines:3"] .skeleton__line:nth-child(2),
.skeleton__lines[style*="--lines:4"] .skeleton__line:nth-child(2),
.skeleton__lines[style*="--lines:5"] .skeleton__line:nth-child(2),
.skeleton__lines[style*="--lines:6"] .skeleton__line:nth-child(2) { display: block; width: 92%; }
.skeleton__lines[style*="--lines:3"] .skeleton__line:nth-child(3),
.skeleton__lines[style*="--lines:4"] .skeleton__line:nth-child(3),
.skeleton__lines[style*="--lines:5"] .skeleton__line:nth-child(3),
.skeleton__lines[style*="--lines:6"] .skeleton__line:nth-child(3) { display: block; width: 96%; }
.skeleton__lines[style*="--lines:4"] .skeleton__line:nth-child(4),
.skeleton__lines[style*="--lines:5"] .skeleton__line:nth-child(4),
.skeleton__lines[style*="--lines:6"] .skeleton__line:nth-child(4) { display: block; width: 88%; }
.skeleton__lines[style*="--lines:5"] .skeleton__line:nth-child(5),
.skeleton__lines[style*="--lines:6"] .skeleton__line:nth-child(5) { display: block; width: 94%; }
.skeleton__lines[style*="--lines:6"] .skeleton__line:nth-child(6) { display: block; width: 70%; }
.skeleton--animated .skeleton__avatar, .skeleton--animated .skeleton__line {
background: linear-gradient(90deg, #24143018 25%, #2414301f 37%, #24143018 63%); background-size: 400% 100%; }
@keyframes skeleton-shimmer { 0% { background-position: 100% 0; } 100% { background-position: 0 0; } }
@media (prefers-reduced-motion: no-preference) {
.skeleton--animated .skeleton__avatar, .skeleton--animated .skeleton__line { animation: skeleton-shimmer .2s ease infinite; }
}
</style><div role="status" aria-label="Loading content" class="skeleton-tw skeleton-tw--text skeleton-tw--animated flex items-start gap-3 w-64">
<span class="sr-only">Loading content</span>
<div aria-hidden="true" class="skeleton-tw__avatar hidden w-11 h-11 rounded-full bg-[#24143018] flex-shrink-0"></div>
<div aria-hidden="true" class="skeleton-tw__lines flex-1 flex flex-col gap-2" style="--lines:3;">
<span class="skeleton-tw__line block h-2.5 rounded-full bg-[#24143018] w-full"></span>
<span class="skeleton-tw__line h-2.5 rounded-full bg-[#24143018] w-[92%]"></span>
<span class="skeleton-tw__line h-2.5 rounded-full bg-[#24143018] w-[96%]"></span>
<span class="skeleton-tw__line h-2.5 rounded-full bg-[#24143018] w-[88%]"></span>
<span class="skeleton-tw__line h-2.5 rounded-full bg-[#24143018] w-[94%]"></span>
<span class="skeleton-tw__line h-2.5 rounded-full bg-[#24143018] w-[70%]"></span>
</div>
</div>
<style>
.skeleton-tw--avatar .skeleton-tw__avatar { display: block; }
.skeleton-tw--card { flex-direction: column; }
.skeleton-tw--card .skeleton-tw__avatar { display: block; width: 100%; height: 120px; border-radius: 10px; }
.skeleton-tw__lines > .skeleton-tw__line:nth-child(n+2) { display: none; }
.skeleton-tw__lines[style*="--lines:2"] > .skeleton-tw__line:nth-child(2),
.skeleton-tw__lines[style*="--lines:3"] > .skeleton-tw__line:nth-child(-n+3),
.skeleton-tw__lines[style*="--lines:4"] > .skeleton-tw__line:nth-child(-n+4),
.skeleton-tw__lines[style*="--lines:5"] > .skeleton-tw__line:nth-child(-n+5),
.skeleton-tw__lines[style*="--lines:6"] > .skeleton-tw__line:nth-child(-n+6) { display: block; }
.skeleton-tw--animated .skeleton-tw__avatar, .skeleton-tw--animated .skeleton-tw__line {
background: linear-gradient(90deg, #24143018 25%, #2414301f 37%, #24143018 63%); background-size: 400% 100%; }
@keyframes skeleton-tw-shimmer { 0% { background-position: 100% 0; } 100% { background-position: 0 0; } }
@media (prefers-reduced-motion: no-preference) {
.skeleton-tw--animated .skeleton-tw__avatar, .skeleton-tw--animated .skeleton-tw__line { animation: skeleton-tw-shimmer .2s ease infinite; }
}
</style>export function Skeleton({
label = "Loading content",
shape = "text",
lines = 3,
animated = true,
}) {
const widths = ["100%", "92%", "96%", "88%", "94%", "70%"];
const shimmer = animated
? { background: "linear-gradient(90deg, #24143018 25%, #2414301f 37%, #24143018 63%)", backgroundSize: "400% 100%" }
: { background: "#24143018" };
const shimmerClass = animated ? "skel-shimmer" : undefined;
return (
<div role="status" aria-label={label} style={{ display: "flex", alignItems: shape === "card" ? "stretch" : "flex-start",
flexDirection: shape === "card" ? "column" : "row", gap: 12, width: 260 }}>
{animated && <span style={{ position: "absolute", width: 1, height: 1, overflow: "hidden", clip: "rect(0 0 0 0)" }}>{label}</span>}
{shape !== "text" && (
<div aria-hidden="true" className={shimmerClass} style={{ width: shape === "card" ? "100%" : 44, height: shape === "card" ? 120 : 44,
borderRadius: shape === "card" ? 10 : "50%", flexShrink: 0, ...shimmer }} />
)}
<div aria-hidden="true" style={{ flex: 1, display: "flex", flexDirection: "column", gap: 8 }}>
{widths.slice(0, lines).map((w, i) => (
<span key={i} className={shimmerClass} style={{ height: 10, borderRadius: 5, width: w, ...shimmer }} />
))}
</div>
<style>{`
@media (prefers-reduced-motion: no-preference) {
.skel-shimmer { animation: skeleton-react-shimmer 1.4s ease infinite; }
@keyframes skeleton-react-shimmer { 0% { background-position: 100% 0; } 100% { background-position: 0 0; } }
}
`}</style>
</div>
);
}