Skeleton Shimmer

Moving highlight across loading placeholders.

Loading content…

html

<div class="mot-shm-stage" data-shape="text-lines" aria-hidden="true">
  <div class="mot-shm-avatar"></div>
  <div class="mot-shm-lines">
    <span class="mot-shm-bar mot-shm-bar--w"></span>
    <span class="mot-shm-bar mot-shm-bar--m"></span>
    <span class="mot-shm-bar mot-shm-bar--s"></span>
  </div>
</div>
<p role="status" aria-live="polite" class="mot-shm-status">Loading content&hellip;</p>
<style>
.mot-shm-stage { width: 100%; max-width: 320px; padding: 16px; background: #FAF7F2; border: 1px solid #24143022; border-radius: 12px; display: flex; gap: 12px; align-items: center; }
.mot-shm-avatar { display: none; width: 40px; height: 40px; border-radius: 999px; background: #24143014; flex: none; }
[data-shape="avatar-row"] .mot-shm-avatar { display: block; }
.mot-shm-lines { flex: 1; display: flex; flex-direction: column; gap: 8px; }
.mot-shm-bar { display: block; height: 12px; border-radius: 6px; background: #24143014; background-image: linear-gradient(90deg, #24143014 0%, #FAF7F2 50%, #24143014 100%); background-size: 200% 100%; }
.mot-shm-bar--w { width: 100%; } .mot-shm-bar--m { width: 80%; } .mot-shm-bar--s { width: 55%; }
.mot-shm-status { margin: 10px 0 0; font: 13px system-ui, sans-serif; color: #241430aa; }
@media (prefers-reduced-motion: no-preference) {
  .mot-shm-bar { animation: mot-shm-sweep 1400ms linear infinite; }
  @keyframes mot-shm-sweep { from { background-position: 200% 0; } to { background-position: -200% 0; } }
}
</style>

tailwind

<div class="w-full max-w-[320px] p-4 bg-[#FAF7F2] border border-[#24143022] rounded-xl flex gap-3 items-center" data-shape="text-lines" aria-hidden="true">
  <div class="tw-shm-avatar hidden w-10 h-10 rounded-full bg-[#24143014] flex-none"></div>
  <div class="flex-1 flex flex-col gap-2">
    <span class="tw-shm-bar block h-3 rounded-md w-full" style="background-image:linear-gradient(90deg,#24143014 0%,#FAF7F2 50%,#24143014 100%); background-size:200% 100%;"></span>
    <span class="tw-shm-bar block h-3 rounded-md w-4/5" style="background-image:linear-gradient(90deg,#24143014 0%,#FAF7F2 50%,#24143014 100%); background-size:200% 100%;"></span>
    <span class="tw-shm-bar block h-3 rounded-md w-3/5" style="background-image:linear-gradient(90deg,#24143014 0%,#FAF7F2 50%,#24143014 100%); background-size:200% 100%;"></span>
  </div>
</div>
<p role="status" aria-live="polite" class="mt-2.5 text-sm text-[#241430]/70">Loading content&hellip;</p>
<style>
[data-shape="avatar-row"] .tw-shm-avatar { display: block; }
@media (prefers-reduced-motion: no-preference) {
  .tw-shm-bar { animation: mot-shm-tw-sweep 1400ms linear infinite; }
  @keyframes mot-shm-tw-sweep { from { background-position: 200% 0; } to { background-position: -200% 0; } }
}
</style>

react

export function SkeletonShimmer({
  shimmer = true,
  duration = 1400,
  shape = "text-lines",
  accent = "#FAF7F2",
}) {
  const barStyle = { display: "block", height: 12, borderRadius: 6, backgroundImage: `linear-gradient(90deg, #24143014 0%, ${accent} 50%, #24143014 100%)`, backgroundSize: "200% 100%" };
  return (
    <div>
      <div aria-hidden="true" style={{ width: "100%", maxWidth: 320, padding: 16, background: "#FAF7F2", border: "1px solid #24143022", borderRadius: 12, display: "flex", gap: 12, alignItems: "center" }}>
        {shape === "avatar-row" && <div style={{ width: 40, height: 40, borderRadius: 999, background: "#24143014", flex: "none" }} />}
        <div style={{ flex: 1, display: "flex", flexDirection: "column", gap: 8 }}>
          <span className="bar" style={{ ...barStyle, width: "100%" }} />
          <span className="bar" style={{ ...barStyle, width: "80%" }} />
          <span className="bar" style={{ ...barStyle, width: "55%" }} />
        </div>
      </div>
      <p role="status" aria-live="polite" style={{ margin: "10px 0 0", fontSize: 13, color: "#241430aa" }}>Loading content&hellip;</p>
      <style>{`
        @media (prefers-reduced-motion: no-preference) {
          ${shimmer ? `.bar { animation: mot-shm-sweep ${duration}ms linear infinite; }` : ""}
          @keyframes mot-shm-sweep { from { background-position: 200% 0; } to { background-position: -200% 0; } }
        }
      `}</style>
    </div>
  );
}