Skeleton Caching

How Caching Works

UI States can cache generated skeleton structures in sessionStorage. This allows instant skeleton display on subsequent loads, even before your content renders for the first time.

Enable Caching

Enable caching with the enableCache and cacheKey props:

typescript
<UIStates
data={data}
loading={loading}
enableCache={true}
cacheKey="user-profile"
>
<div>
<h1>{data.name}</h1>
<p>{data.email}</p>
</div>
</UIStates>

Cache Key

The cacheKey should be unique per component/view. Use descriptive keys that reflect the content:

typescript
// Different cache keys for different views
<UIStates cacheKey="user-profile" enableCache>...</UIStates>
<UIStates cacheKey="user-settings" enableCache>...</UIStates>
<UIStates cacheKey="product-list" enableCache>...</UIStates>
// Dynamic cache keys
<UIStates cacheKey={`product-${productId}`} enableCache>...</UIStates>

Cache Lifetime

Cached skeletons are stored in sessionStorage and automatically invalidated:

  • After 5 minutes (time-based invalidation)
  • When viewport width changes by more than 50px (responsive invalidation)
  • When the browser session ends (sessionStorage clears)

Cache Flow

  • First load: Default skeleton shown, then content renders
  • Content renders: UI States measures DOM and saves to sessionStorage
  • Subsequent loads: Cached skeleton shown instantly during loading
  • Content renders: Real content replaces skeleton

Benefits

Without CacheWith Cache
Generic skeleton on every loadAccurate skeleton instantly
Layout shift when content loadsSmooth transition, less CLS
Skeleton doesn't match contentPerfect match from cache

Complete Example

typescript
function UserDashboard() {
const query = useQuery({
queryKey: ["dashboard"],
queryFn: fetchDashboard,
});
return (
<UIStates
query={query}
enableCache={true}
cacheKey="dashboard-main"
>
<div className="grid grid-cols-3 gap-4">
<StatsCard title="Users" value={query.data.users} />
<StatsCard title="Revenue" value={query.data.revenue} />
<StatsCard title="Orders" value={query.data.orders} />
</div>
<div className="mt-8">
<h2 className="text-xl font-bold">Recent Activity</h2>
<ActivityList items={query.data.activity} />
</div>
</UIStates>
);
}
Caching is especially useful for complex layouts with many elements. The skeleton will perfectly match your grid, cards, and text elements from the first cached load.