Cache responses in memory or sessionStorage to eliminate redundant network requests.
Basic Caching
Add data-cache to cache GET responses:
<!-- Cache for 5 minutes (default) --><nav data-cache> <a href="/dashboard" data-target="#main">Dashboard</a> <a href="/settings" data-target="#main">Settings</a></nav> <!-- Cache for a specific duration --><a href="/api/stats" data-cache="30s" data-target="#stats">Refresh</a>
Duration Strings
| Value | Duration |
|---|---|
true or "" | 5 minutes (default) |
30s | 30 seconds |
5m | 5 minutes |
1h | 1 hour |
1d | 1 day |
When a cached response is available, html★ skips the network request entirely and swaps the cached HTML.
Stale-While-Revalidate (SWR)
SWR serves cached content instantly, then revalidates in the background:
<!-- Serve stale content immediately, revalidate behind the scenes --><div data-cache="swr:5m" data-href="/api/notifications" data-trigger="load" data-target="self"> Loading...</div>
With SWR:
- Cache hit (fresh) — serves cached content, no fetch
- Cache hit (stale) — serves stale content immediately, fetches in background, swaps when response arrives
- Cache miss — fetches normally
Use data-cache="swr" for the default 5-minute TTL, or data-cache="swr:30s" for a custom duration.
Persistent Storage
By default, cache lives in memory and is lost on page refresh. Use data-cache-storage to persist to sessionStorage:
<nav data-cache="5m" data-cache-storage="session"> <a href="/products" data-target="#main">Products</a> <a href="/orders" data-target="#main">Orders</a></nav>
Session-backed cache survives page refreshes and lives for the browser tab's lifetime. Memory cache is checked first, with sessionStorage as a fallback.
Cache Invalidation
Use data-cache-invalidate on non-GET requests to clear cached URLs when data changes:
<!-- This form submission invalidates the products cache --><form action="/products" data-target="#products" data-cache-invalidate="/products"> <input name="name" required> <button>Add Product</button></form>
Multiple patterns (comma-separated):
<form action="/api/settings" data-target="#result" data-cache-invalidate="/api/settings, /api/dashboard"> ...</form>
Patterns are matched as regular expressions against cached URLs. Invalidation runs automatically when a non-GET request succeeds.
Cascade
data-cache inherits through the attribute cascade, so you can set it on a parent:
<div data-target="#main" data-cache="5m"> <!-- All links inherit data-cache="5m" --> <a href="/page-1">Page 1</a> <a href="/page-2">Page 2</a> <a href="/page-3">Page 3</a></div>
JavaScript API
Control the cache programmatically:
<h2>Prefetching</h2><p>Prefetch loads pages into the cache before the user clicks, using <code>data-prefetch</code>:</p><code-block language="html"><!-- Prefetch on hover (default) --><nav data-prefetch data-target="#main"> <a href="/about">About</a> <a href="/pricing">Pricing</a></nav> <!-- Prefetch with hover delay --><a href="/heavy-page" data-prefetch="hover:300" data-target="#main">Heavy Page</a> <!-- Prefetch when scrolled into view --><a href="/section-2" data-prefetch="visible" data-target="#main">Section 2</a> <!-- Prefetch immediately on page load --><a href="/critical-page" data-prefetch="eager" data-target="#main">Critical</a>
| Mode | Behavior |
|---|---|
hover | Prefetch on mouseenter (default) |
hover:<ms> | Prefetch after hovering for specified milliseconds |
visible | Prefetch when element scrolls into viewport |
eager | Prefetch immediately on page load |
false | Disable prefetching |
Prefetched responses are stored in cache with the element's data-cache TTL (default 5 minutes). Only GET requests are prefetched. data-prefetch inherits through the cascade.
You can also prefetch programmatically:
<h2>Examples</h2><h3>Cached Navigation</h3><code-block language="html"><nav data-target="#main" data-cache="10m" data-cache-storage="session"> <a href="/">Home</a> <a href="/about">About</a> <a href="/contact">Contact</a></nav><main id="main"></main>
Navigation responses are cached for 10 minutes in sessionStorage. Back/forward navigation feels instant.
Dashboard with SWR
<div data-cache="swr:1m"> <div data-href="/api/revenue" data-trigger="load" data-target="self"> Loading revenue... </div> <div data-href="/api/orders" data-trigger="load" data-target="self"> Loading orders... </div></div>
Dashboard widgets show the last known data instantly, then quietly update when fresh data arrives.
Form with Cache Invalidation
<div data-cache="5m"> <a href="/todos" data-target="#list">Refresh</a></div> <div id="list"></div> <form action="/todos" data-method="post" data-target="#list" data-cache-invalidate="/todos"> <input name="title" placeholder="New todo"> <button>Add</button></form>
Adding a todo invalidates the cached list, so the next "Refresh" click fetches fresh data.