Server HTML first.
Islands where it matters.
Ilha is a tiny, isomorphic UI library. You write function components withatom() state, render them to HTML on the server, and hydrate only the regions that need JavaScript.
Try this tasks island live in the playground.
- Virtual DOM
- None
- Compiler
- None
- Component for server and client
- One
- Hydration
- Opt-in
The islands model
Most of your page is HTML. Keep it that way.
Use Ilha when you want server HTML plus a few interactive regions, not a full client app by default. Four steps cover the whole mental model.
- 1Write a component that returns JSX.
() => JSX - 2Declare atom() values you read in the view.
atom() - 3Render the component to HTML on the server.
await renderToString() - 4Hydrate that HTML in the browser.
mount(..., { hydrate: true })
01Components
Write a function. Return HTML-shaped JSX.
A component is a function that returns JSX. You declare atom() values inside it, and markup, state, and events stay in one file you can read top to bottom.
- Plain functions, no classes or hooks rules to learn
- Lowercase native events: onclick, oninput
- Interpolations escape by default
02Fine-grained reactivity
Update only the component that changed.
Reading an atom subscribes the component that read it. A write reruns only that component and morphs its host DOM, with no virtual DOM diffing a whole tree.
- Derived values with Atom.map and Atom.transform
- Effect Streams for debounce, merge, and live feeds
- when() interrupts stale async work
03Isomorphic rendering
Render on the server. Hydrate in the browser.
You call await renderToString() on the server and mount() with hydrate: true in the browser. The same function runs in both places, so you never split server and client copies.
- Runs in Node, Bun, and edge runtimes without a DOM polyfill
- Atom snapshots travel with the HTML
- Every island hydrates on its own
Grow when you need to
Start with one package. Add the rest later.
The core package covers components, atoms, and rendering. Add file-system routing, context, or the Astro integration when your project asks for them.
- @ilha/router: file-system routes and server islands
- createContext() for values shared across a subtree
- @ilha/astro: Ilha components as Astro islands
Start a project
Scaffold a starter in one command.
Pick a template, name your project, and copy the command. Each starter is a small, type-safe project you can read in a few minutes.
Prefer to set it up yourself? Follow the installation guide.
Ready to build?
Build your first component in five minutes.
Read the introduction, or follow the counter tutorial from atom() to events to server rendering.