Skeleton Screen

Loading placeholder shaped like final content.

Weekly digest Three updates since your last visit, summarised below.

html

<div class="skl" role="status" aria-label="Content loading">
  <div class="skl__avatar" style="background:#A8E6C1;"></div>
  <div class="skl__lines">
    <span class="skl__line skl__line--title">Weekly digest</span>
    <span class="skl__line skl__line--body">Three updates since your last visit, summarised below.</span>
  </div>
</div>
<style>
.skl { font: 13px/1.5 system-ui, sans-serif; color: #241430; background: #FAF7F2; padding: 18px; border-radius: 12px; width: 300px; box-sizing: border-box; display: flex; gap: 12px; align-items: flex-start; }
.skl__avatar { width: 40px; height: 40px; border-radius: 50%; background: #24143014; flex-shrink: 0; }
.skl__lines { flex: 1; display: flex; flex-direction: column; gap: 8px; padding-top: 4px; }
.skl__line { display: block; height: 12px; border-radius: 4px; background: #24143014; color: transparent; overflow: hidden; }
.skl__line--title { width: 60%; height: 14px; }
.skl--loaded .skl__avatar { background: var(--acc, #A8E6C1); }
.skl--loaded .skl__line { width: auto; height: auto; background: none; color: #241430; font-weight: 400; }
.skl--loaded .skl__line--title { font-weight: 700; font-size: 14px; }
.skl--loaded .skl__line--body { font-size: 12px; color: #24143099; }
@media (prefers-reduced-motion: no-preference) {
  .skl__line, .skl__avatar { background-image: linear-gradient(90deg, #24143014 25%, #24143024 37%, #24143014 63%); background-size: 400% 100%; animation: skl-shimmer 1.4s ease infinite; }
  .skl--loaded .skl__line, .skl--loaded .skl__avatar { animation: none; background-image: none; }
}
@keyframes skl-shimmer { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }
</style>

tailwind

<div class="skltw font-sans text-[#241430] bg-[#FAF7F2] p-4.5 rounded-xl w-[300px] box-border flex gap-3 items-start" role="status" aria-label="Content loading">
  <div class="skltw__avatar w-10 h-10 rounded-full bg-[#24143014] shrink-0" style="--acc:#A8E6C1;"></div>
  <div class="flex-1 flex flex-col gap-2 pt-1">
    <span class="skltw__line skltw__line--title block h-3.5 w-3/5 rounded bg-[#24143014]">Weekly digest</span>
    <span class="skltw__line block h-3 rounded bg-[#24143014]">Three updates since your last visit, summarised below.</span>
  </div>
</div>
<style>
.skltw--loaded .skltw__avatar { background: var(--acc); }
.skltw--loaded .skltw__line { width: auto; height: auto; background: none; color: #241430; }
.skltw--loaded .skltw__line--title { font-weight: 700; font-size: 14px; }
@media (prefers-reduced-motion: no-preference) {
  .skltw__line, .skltw__avatar { background-image: linear-gradient(90deg, #24143014 25%, #24143024 37%, #24143014 63%); background-size: 400% 100%; animation: skltw-shimmer 1.4s ease infinite; }
  .skltw--loaded .skltw__line, .skltw--loaded .skltw__avatar { animation: none; background-image: none; }
}
@keyframes skltw-shimmer { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }
</style>

react

export function SkeletonScreen({
  loaded = false,
  title = "Weekly digest",
  body = "Three updates since your last visit, summarised below.",
  accent = "#A8E6C1",
}) {
  const line = { display: "block", borderRadius: 4, background: loaded ? "none" : "#24143014", color: loaded ? "#241430" : "transparent", overflow: "hidden" };
  return (
    <div role="status" aria-label={loaded ? "Content loaded" : "Content loading"} style={{ font: "13px/1.5 system-ui, sans-serif", color: "#241430", background: "#FAF7F2", padding: 18, borderRadius: 12, width: 300, boxSizing: "border-box", display: "flex", gap: 12, alignItems: "flex-start" }}>
      <div style={{ width: 40, height: 40, borderRadius: "50%", background: loaded ? accent : "#24143014", flexShrink: 0 }} />
      <div style={{ flex: 1, display: "flex", flexDirection: "column", gap: 8, paddingTop: 4 }}>
        <span style={{ ...line, width: loaded ? "auto" : "60%", height: loaded ? "auto" : 14, fontWeight: 700, fontSize: 14 }}>{title}</span>
        <span style={{ ...line, height: loaded ? "auto" : 12, fontSize: 12, color: loaded ? "#24143099" : "transparent" }}>{body}</span>
      </div>
    </div>
  );
}