Stale State

Displayed data may no longer be current.

This data may be out of date.

Updated 18 minutes ago

html

<div class="stale stale--notice" role="status" aria-live="polite">
  <span class="stale__icon" aria-hidden="true">⟳</span>
  <div class="stale__body">
    <p class="stale__message">This data may be out of date.</p>
    <p class="stale__meta">Updated 18 minutes ago</p>
  </div>
  <button type="button" class="stale__refresh">Refresh</button>
</div>
<style>
.stale { display: flex; align-items: center; gap: 10px; max-width: 380px; padding: 10px 14px; box-sizing: border-box;
  border-radius: 9px; font: 13px/1.4 system-ui, sans-serif; color: #241430; border: 1px solid; }
.stale--notice { background: color-mix(in srgb, #D9C8F0 40%, #FAF7F2); border-color: #8A6FBF; }
.stale--notice .stale__icon { color: #8A6FBF; }
.stale--warning { background: color-mix(in srgb, #E8A020 18%, #FAF7F2); border-color: #B4790A; }
.stale--warning .stale__icon { color: #B4790A; }
.stale__icon { font-size: 16px; flex-shrink: 0; }
.stale__body { flex: 1; }
.stale__message { margin: 0; font-weight: 700; }
.stale__meta { margin: 2px 0 0; color: #241430b3; font-size: 11.5px; }
.stale__refresh { border: 1px solid #241430; background: transparent; color: #241430; border-radius: 6px;
  font: 600 11.5px system-ui, sans-serif; padding: 5px 10px; cursor: pointer; white-space: nowrap; }
.stale__refresh:hover { background: #24143012; }
.stale__refresh:focus-visible { outline: 2px solid #241430; outline-offset: 2px; }
</style>

tailwind

<div role="status" aria-live="polite" class="stale-tw stale-tw--notice flex items-center gap-2.5 max-w-sm px-3.5 py-2.5 box-border rounded-lg border font-sans text-[13px] text-[#241430]">
  <span aria-hidden="true" class="stale-tw__icon text-base flex-shrink-0">⟳</span>
  <div class="flex-1">
    <p class="m-0 font-bold">This data may be out of date.</p>
    <p class="mt-0.5 mb-0 text-[#241430]/70 text-[11.5px]">Updated 18 minutes ago</p>
  </div>
  <button type="button" class="border border-[#241430] bg-transparent text-[#241430] rounded-md font-semibold text-[11.5px] px-2.5 py-1.5 cursor-pointer whitespace-nowrap hover:bg-black/5">Refresh</button>
</div>
<style>
.stale-tw--notice { background: color-mix(in srgb, #D9C8F0 40%, #FAF7F2); border-color: #8A6FBF; }
.stale-tw--notice .stale-tw__icon { color: #8A6FBF; }
.stale-tw--warning { background: color-mix(in srgb, #E8A020 18%, #FAF7F2); border-color: #B4790A; }
.stale-tw--warning .stale-tw__icon { color: #B4790A; }
</style>

react

export function StaleState({
  message = "This data may be out of date.",
  lastUpdated = "18 minutes ago",
  severity = "notice",
  showRefresh = true,
}) {
  const palette = {
    notice: { bg: "color-mix(in srgb, #D9C8F0 40%, #FAF7F2)", border: "#8A6FBF", icon: "#8A6FBF" },
    warning: { bg: "color-mix(in srgb, #E8A020 18%, #FAF7F2)", border: "#B4790A", icon: "#B4790A" },
  }[severity] ?? { bg: "#FAF7F2", border: "#8A6FBF", icon: "#8A6FBF" };
  return (
    <div role="status" aria-live="polite" style={{ display: "flex", alignItems: "center", gap: 10, maxWidth: 380,
      padding: "10px 14px", boxSizing: "border-box", borderRadius: 9, font: "13px/1.4 system-ui, sans-serif",
      color: "#241430", border: `1px solid ${palette.border}`, background: palette.bg }}>
      <span aria-hidden="true" style={{ fontSize: 16, flexShrink: 0, color: palette.icon }}>⟳</span>
      <div style={{ flex: 1 }}>
        <p style={{ margin: 0, fontWeight: 700 }}>{message}</p>
        <p style={{ margin: "2px 0 0", color: "#241430b3", fontSize: 11.5 }}>Updated {lastUpdated}</p>
      </div>
      {showRefresh && (
        <button type="button" style={{ border: "1px solid #241430", background: "transparent", color: "#241430",
          borderRadius: 6, fontWeight: 600, fontSize: 11.5, padding: "5px 10px", cursor: "pointer", whiteSpace: "nowrap" }}>Refresh</button>
      )}
    </div>
  );
}