MPA → instant SPA · ~5 KB gzipped

Your website,
made instant.

Sparke makes traditional multi-page sites behave like a true Single Page Application. Standard hyperlinks become instant page swaps - say goodbye to full page reloads.

$ cdn.jsdelivr.net/gh/benshawuk/sparke
index.html
~5 KBgzipped
0dependencies
0build steps
1script tag
The core idea

Other libraries hit the network after you click. Sparke does it before.

HTMX, Turbo, Livewire, Inertia, Phoenix LiveView, Astro etc. all wait for the click, then make the request - so nothing happens on screen until the server responds. Even with preloading, they still reach for the network when it matters. Sparke flips the order: every page is already loaded before you click, so navigation is literally instant - the snappy feel of a true SPA, without the round trip.

How it works

Four moves, zero ceremony.

No diffing, no virtual DOM, no hydration - just discover, preload, intercept, swap.
Open any step below: every page here is served by Sparke, so the navigation itself is the demo.

In practice

Zero-config by design.
Control when you need it.

There's no JavaScript API and no global object - just one script tag, a few optional attributes, and four events.

<!-- one tag in <head>. defer, and you're done. -->
<script src="/js/sparke.min.js" defer></script>

<!-- no JS? it's just a normal MPA. -->
<!-- skip pages a swap would break -->
<script
  src="sparke.min.js"
  defer
  data-ignore="/admin/* /checkout /logout"
></script>

<!-- per-link opt-out: force a full navigation -->
<a href="/legacy/billing" rel="external">Billing portal</a>
<main>
  <canvas id="chart"></canvas>

  <!-- re-runs on every swap into this page -->
  <script data-sparke-rerun>
    initChart(document.getElementById("chart"));
  </script>
</main>
// four events on window. that's the whole API.
window.addEventListener("sparke:after-swap", (e) => {
  initWidgets();
  trackPageview(new URL(e.detail.to).pathname);
});

// cancel a navigation — e.g. unsaved changes
window.addEventListener("sparke:before-swap", (e) => {
  if (formIsDirty()) e.preventDefault();
});
What you get

Instant, but it still plays by the rules.

Fails safely

Pure progressive enhancement. No fetch or History API? The browser just behaves as a normal MPA.

Works offline

Preloaded pages live in memory, so you can drop the connection and keep navigating the whole site.

SEO intact

Every page is still a complete, server-rendered document. No hydration step, no client-render tax.

View Transitions

Add data-transitions for a free crossfade on every swap, with shared-element morphs when you want them.

Plays nice

Runs happily alongside Alpine, HTMX, Livewire, Astro, vanilla JS or any standard HTML site.
hx-* forms are left untouched.

Accessible

After each swap, focus moves to <main> and the new title is announced via an aria-live region.

Drop it in

Make your site feel instant in one line.

Self-host the 5 KB file, or pull it straight from the CDN.
No package, no bundler, no config.

via CDN
<script src="https://cdn.jsdelivr.net/gh/benshawuk/sparke@1/sparke.min.js" defer></script>