Single-file components.
Markup, script and style in one .html file. Nothing rewrites your code.
no compiler·no virtual DOM·no build step
Import a component straight from a URL — no install, no bundler. The browser fetches the .html and boots it live. Components are just files, anywhere. Nothing else does that.
The component is the file. Save counter.html and the browser runs it byte-for-byte — reactive, scoped, untouched. Nothing else does that.
The template is the backend. spark-ssr reads this file and infers the database, REST API, validation and hydration — no server file, no ORM, no build. Read the SSR docs →
bunx create-spark-html-app@latest
CPU speed — vs hand-written vanilla JS (geomean, lower is better)
krausest js-framework-benchmark, paired local run, spark-html 1.8 — past Vue (1.31), and the only one here with no compiler and no build step. Run memory holds ~1.45× vanilla; in-place state mutation is the fast path. method & full table
“{q.text}” — {q.author}
“Spark-html is what web frameworks could've been if we didn't spend 21 years bolting JS frameworks on top of HTML instead of just reading the HTML.” — Anon9
“The scanner-not-parser tradeoff is the real genius: no compiler means no build step, and the runtime learns the dependency graph by observing what each expression reads during evaluation. It turns the "no compiler" constraint into a self-adapting system.” — Anon10
“Self-healing compiled functions, three-tier expression evaluation, column sweeps for keyed rows, dirty-item tracking for deep mutations — most frameworks pick one reactivity strategy. Spark layers four of them and lets the runtime choose, all hidden behind {name} and each="item in items".” — Anon11
“Dependency sets that only grow, a runtime that drops and rebuilds its own fast paths on failure — closer to biological memory than cache invalidation. It observes, learns, remembers, and heals.” — Anon12
<div import="https://cdn.jsdelivr.net/gh/wilkinnovo/
spark-html/website/public/components/url-card.html">
</div>
● live — fetched from a CDN, no bundler
This whole component is a plain .html file on a CDN — no bundler touched it.
<h2>Count: {count}</h2> <button onclick={inc}>+1</button> <script> let count = 0; function inc() { count++; } </script>
● live — the actual component
<input bind:value="draft"><button onclick={add}>Add</button> <template each="t in todos"> <input type="checkbox" bind:checked="t.done" onchange={patch}> {t.title} <button onclick={remove}>✕</button> </template> <spark-ssr table="todos" live />
● live — same template in this page; the inferred API call shows below (server simulated — this site is static)
→
Why Spark
AI writes more of the web every day. Spark is for the people who still love writing it themselves — view-source romantics, hand-crafters, the ones who want to understand every line they ship. So it gets out of your way: no compiler rewriting your code, no virtual DOM between you and the page, no build step between you and the browser. The HTML you write is the app that runs.
What's in Spark
Markup, script and style in one .html file. Nothing rewrites your code.
A change re-evaluates only the bindings that read it — not the page.
Named stores let any two components share state. No providers.
<template route> + router(). Active links and a route store, free.
Real HTML per route at build time. No SSR server, no app changes.
spark-ssr: the template is the backend — inferred database, REST, auth & hydration. No server file. SSR docs →
theme() — dark / light / system, persisted, no flash.
Use it — no build required
<script type="importmap"> { "imports": { "spark-html": "https://esm.sh/spark-html@1" } } </script> <script type="module"> import { mount } from 'spark-html'; mount(); </script>
<div import="components/card"></div> <!-- …or straight from anywhere --> <div import="https://cdn.jsdelivr.net/ gh/you/repo/card.html"></div>
Serve any static folder (bunx serve) — no install, no bundler, no compiler. Read the docs →
Built with Spark
View all →