#Installation
ilha can be installed with your package manager of choice.
#Install
npm install ilhayarn add ilhapnpm add ilhabun add ilhadeno add npm:ilha#Templates
If you want to start from a ready-made project instead of wiring everything manually, use one of the official templates.
| Template | Command | Sandbox |
|---|---|---|
| Vite | npx giget@latest gh:ilhajs/ilha/templates/vite | Open |
| Hono | npx giget@latest gh:ilhajs/ilha/templates/hono | Open |
| Nitro | npx giget@latest gh:ilhajs/ilha/templates/nitro | Open |
| Elysia | npx giget@latest gh:ilhajs/ilha/templates/elysia | — |
| Electrobun | npx giget@latest gh:ilhajs/ilha/templates/electrobun | — |
Templates are the fastest way to get a working project structure for SSR, routing, and deployment targets without setting everything up from scratch.
#Requirements
ilha is designed for modern JavaScript and TypeScript projects.
- Use it in apps that can run ESM modules.
- Use TypeScript if you want the best editor support.
- Use a browser environment for mounting and hydration.
#Import
import const ilha: IlhaBuilder<Record<string, unknown>, Record<string, never>, Record<string, never>> & {
html: (strings: TemplateStringsArray, ...values: unknown[]) => RawHtml;
raw: (value: string) => RawHtml;
mount: (registry: IslandRegistry, options?: MountOptions) => MountResult;
from: <TInput, TStateMap extends Record<string, unknown>>(selector: string | Element, island: Island<TInput, TStateMap>, props?: Partial<TInput>) => (() => void) | null;
context: <T>(key: string, initial: T) => ContextSignal<...>;
}
ilha , { const html: (strings: TemplateStringsArray, ...values: unknown[]) => RawHtml html , const raw: (value: string) => RawHtml raw , const css: (strings: TemplateStringsArray | string, ...values: (string | number)[]) => string css , const mount: (registry: IslandRegistry, options?: MountOptions) => MountResult mount , const from: <TInput, TStateMap extends Record<string, unknown>>(selector: string | Element, island: Island<TInput, TStateMap>, props?: Partial<TInput>) => (() => void) | null from , const context: <T>(key: string, initial: T) => ContextSignal<T> context } from "ilha";Use the default export for the builder chain, and named exports for helpers such as html, raw, and mount.
#Minimal example
import const ilha: IlhaBuilder<Record<string, unknown>, Record<string, never>, Record<string, never>> & {
html: (strings: TemplateStringsArray, ...values: unknown[]) => RawHtml;
raw: (value: string) => RawHtml;
mount: (registry: IslandRegistry, options?: MountOptions) => MountResult;
from: <TInput, TStateMap extends Record<string, unknown>>(selector: string | Element, island: Island<TInput, TStateMap>, props?: Partial<TInput>) => (() => void) | null;
context: <T>(key: string, initial: T) => ContextSignal<...>;
}
ilha , { const html: (strings: TemplateStringsArray, ...values: unknown[]) => RawHtml html } from "ilha";
const const Counter: Island<Record<string, unknown>, MergeState<Record<string, never>, "count", number>> Counter = const ilha: IlhaBuilder<Record<string, unknown>, Record<string, never>, Record<string, never>> & {
html: (strings: TemplateStringsArray, ...values: unknown[]) => RawHtml;
raw: (value: string) => RawHtml;
mount: (registry: IslandRegistry, options?: MountOptions) => MountResult;
from: <TInput, TStateMap extends Record<string, unknown>>(selector: string | Element, island: Island<TInput, TStateMap>, props?: Partial<TInput>) => (() => void) | null;
context: <T>(key: string, initial: T) => ContextSignal<...>;
}
ilha
.IlhaBuilder<Record<string, unknown>, Record<string, never>, Record<string, never>>.state<number, "count">(key: "count", init?: StateInit<Record<string, unknown>, number> | undefined): IlhaBuilder<Record<string, unknown>, MergeState<Record<string, never>, "count", number>, Record<string, never>> state ("count", 0)
.IlhaBuilder<Record<string, unknown>, MergeState<Record<string, never>, "count", number>, Record<string, never>>.on<"button@click">(selectorOrCombined: "button@click", handler: (ctx: HandlerContextFor<Record<string, unknown>, MergeState<Record<string, never>, "count", number>, "click", Record<string, never>>) => void | Promise<void>): IlhaBuilder<Record<string, unknown>, MergeState<Record<string, never>, "count", number>, Record<string, never>> (+1 overload) on ("button@click", ({ state: IslandState<MergeState<Record<string, never>, "count", number>> state }) => state: IslandState<MergeState<Record<string, never>, "count", number>> state .count: MarkedSignalAccessor
(value: number) => void (+1 overload)
count (state: IslandState<MergeState<Record<string, never>, "count", number>> state .count: MarkedSignalAccessor
() => number (+1 overload)
count () + 1))
.IlhaBuilder<Record<string, unknown>, MergeState<Record<string, never>, "count", number>, Record<string, never>>.render(fn: (ctx: RenderContext<Record<string, unknown>, MergeState<Record<string, never>, "count", number>, Record<string, never>>) => string | RawHtml): Island<Record<string, unknown>, MergeState<Record<string, never>, "count", number>> render (
({ state: IslandState<MergeState<Record<string, never>, "count", number>> state }) => const html: (strings: TemplateStringsArray, ...values: unknown[]) => RawHtml html `
<div>
<p>Count: ${state: IslandState<MergeState<Record<string, never>, "count", number>> state .count: MarkedSignalAccessor
() => number (+1 overload)
count ()}</p>
<button>Increment</button>
</div>
`,
);#Server-side rendering
Render the island to an HTML string with toString():
const const htmlOutput: string htmlOutput = const Counter: Island<Record<string, unknown>, MergeState<Record<string, never>, "count", number>> Counter .Island<Record<string, unknown>, MergeState<Record<string, never>, "count", number>>.toString(props?: Partial<Record<string, unknown>> | undefined): string toString ();If your island uses async derived values, you can also await the island itself:
const const htmlOutput: string htmlOutput = await const Counter: Island
(props?: Partial<Record<string, unknown>> | undefined) => string | Promise<string>
Counter ();#Client-side mounting
Mount the island into a DOM element:
const const root: HTMLElement | null root = var document: Documentwindow.document returns a reference to the document contained in the window.
document .Document.getElementById(elementId: string): HTMLElement | nullThe getElementById() method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById ("app");
if (const root: HTMLElement | null root ) {
const const unmount: () => void unmount = const Counter: Island<Record<string, unknown>, MergeState<Record<string, never>, "count", number>> Counter .Island<Record<string, unknown>, MergeState<Record<string, never>, "count", number>>.mount(host: Element, props?: Partial<Record<string, unknown>> | undefined): () => void mount (const root: HTMLElement root );
}The returned function stops listeners, effects, and other active behavior.