import ilha, { html, mount } from "ilha";
export const Counter = ilha
.state("count", 0)
.derived("doubled", ({ state }) => state.count() * 2)
.on("[data-action=increase]@click", ({ state }) => {
state.count(state.count() + 1);
})
.on("[data-action=decrease]@click", ({ state }) => {
state.count(state.count() - 1);
})
.render(
({ state, derived }) => html`
<p>Count: ${state.count()}</p>
<p>Doubled: ${derived.doubled.value}</p>
<button data-action="increase">Increase</button>
<button data-action="decrease">Decrease</button>
`,
);
mount({ Counter });
Ilha is a tiny island architecture library that renders to plain HTML on the server and hydrates on the client with zero flicker. The core is under 2,500 lines of code — small enough to paste into any AI prompt. And when you need more, the extras are included: routing, typed forms, and shared state management.
At under 2,500 lines of code, the entire source fits in a single AI context window, so your assistant can reason about the whole framework, not just the docs.
Every line is free. No paywalls, no hidden tiers.
Runs from a single import — no transform, no toolchain to wrestle with.
TypeScript, PHP, Ruby, Elixir, Rust, Go — Ilha fits your stack regardless.
Render to plain HTML on the server, hydrate on the client — with zero flicker. Edge rendering supported too.
import { mount } from "ilha";
import { Counter } from "./hero";
// Client side (lazy mount)
mount({ Counter });
// Server side (only initial state)
Counter.toString();
// Server side hydratable (execute derived)
await Counter.hydratable();
Fine-grained reactivity via alien-signals. No diffing, no overhead, no surprises.
const Search = ilha
.state("query", "")
.derived("results", async ({ state, signal }) => {
const url = `/api/search?q=${state.query()}`;
const res = await fetch(url, { signal });
return res.json() as Promise<string[]>;
})
.effect(({ state }) => {
const title = `Search: ${state.query() || "…"}`;
document.title = title;
})
.bind("[name=q]", "query")
.render(({ state, derived }) => html`
<input name="q" placeholder="Search…" />
<!--Render results-->
`);
Ilha goes beyond UI templating. Get routing, typed form binding, and zustand-shaped state management out of the box — no extra setup required.
Install with:
// vite.config.ts
import { pages } from "@ilha/router/vite";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [pages()],
});
// main.ts
// Add routes in src/pages/ and import registered routes
import { pageRouter } from "ilha:pages";