#Render
Finalizes the builder chain and returns a callable Island. This is always the last method in the chain — every other builder method must be called before .render().
#Basic usage
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 MyIsland: Island<Record<string, unknown>, MergeState<Record<string, never>, "x", number>> MyIsland = 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, "x">(key: "x", init?: StateInit<Record<string, unknown>, number> | undefined): IlhaBuilder<Record<string, unknown>, MergeState<Record<string, never>, "x", number>, Record<string, never>> state ("x", 1)
.IlhaBuilder<Record<string, unknown>, MergeState<Record<string, never>, "x", number>, Record<string, never>>.render(fn: (ctx: RenderContext<Record<string, unknown>, MergeState<Record<string, never>, "x", number>, Record<string, never>>) => string | RawHtml): Island<Record<string, unknown>, MergeState<Record<string, never>, "x", number>> render (({ state: IslandState<MergeState<Record<string, never>, "x", number>> state }) => const html: (strings: TemplateStringsArray, ...values: unknown[]) => RawHtml html `<p>${state: IslandState<MergeState<Record<string, never>, "x", number>> state .x: SignalAccessor<number> x }</p>`);#Render context
The render function receives a RenderContext with everything declared in the builder chain:
{
state: IslandState; // reactive state signals
derived: IslandDerived; // derived value envelopes
input: TInput; // resolved input props
}All three are always present, even if not declared. An island with no state gets an empty state object, and so on.
#Return type
The render function must return a string or a RawHtml object. In practice this means returning either a plain template literal or an html\`` tagged template:
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 } from "ilha";
// Plain string — no escaping
const const A: Island<Record<string, unknown>, Record<string, never>> A = 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>>.render(fn: (ctx: RenderContext<Record<string, unknown>, Record<string, never>, Record<string, never>>) => string | RawHtml): Island<Record<string, unknown>, Record<string, never>> render (() => `<p>hello</p>`);
// html`` — safe interpolation with auto-escaping
const const B: Island<Record<string, unknown>, Record<string, never>> B = 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>>.render(fn: (ctx: RenderContext<Record<string, unknown>, Record<string, never>, Record<string, never>>) => string | RawHtml): Island<Record<string, unknown>, Record<string, never>> render (({ state: IslandState<Record<string, never>> state }) => const html: (strings: TemplateStringsArray, ...values: unknown[]) => RawHtml html `<p>${state: IslandState<Record<string, never>> state }</p>`);
// raw() — trusted markup inside html``
const const C: Island<Record<string, unknown>, Record<string, never>> C = 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>>.render(fn: (ctx: RenderContext<Record<string, unknown>, Record<string, never>, Record<string, never>>) => string | RawHtml): Island<Record<string, unknown>, Record<string, never>> render (() => const html: (strings: TemplateStringsArray, ...values: unknown[]) => RawHtml html `<div>${function raw(value: string): RawHtml raw ("<em>trusted</em>")}</div>`);Use html\`` whenever you interpolate dynamic values. Plain strings are fine for fully static markup.
#Conditional rendering
Use standard JavaScript expressions inside the render function:
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 Island: Island<Record<string, unknown>, MergeState<MergeState<MergeState<Record<string, never>, "loading", boolean>, "error", string>, "items", string[]>> Island = 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<boolean, "loading">(key: "loading", init?: StateInit<Record<string, unknown>, boolean> | undefined): IlhaBuilder<Record<string, unknown>, MergeState<Record<string, never>, "loading", boolean>, Record<string, never>> state ("loading", false)
.IlhaBuilder<Record<string, unknown>, MergeState<Record<string, never>, "loading", boolean>, Record<string, never>>.state<string, "error">(key: "error", init?: StateInit<Record<string, unknown>, string> | undefined): IlhaBuilder<Record<string, unknown>, MergeState<MergeState<Record<string, never>, "loading", boolean>, "error", string>, Record<string, never>> state ("error", "")
.IlhaBuilder<Record<string, unknown>, MergeState<MergeState<Record<string, never>, "loading", boolean>, "error", string>, Record<string, never>>.state<string[], "items">(key: "items", init?: StateInit<Record<string, unknown>, string[]> | undefined): IlhaBuilder<Record<string, unknown>, MergeState<MergeState<MergeState<Record<string, never>, "loading", boolean>, "error", string>, "items", string[]>, Record<string, never>> state ("items", [] as string[])
.IlhaBuilder<Record<string, unknown>, MergeState<MergeState<MergeState<Record<string, never>, "loading", boolean>, "error", string>, "items", string[]>, Record<...>>.render(fn: (ctx: RenderContext<Record<string, unknown>, MergeState<MergeState<MergeState<Record<string, never>, "loading", boolean>, "error", string>, "items", string[]>, Record<string, never>>) => string | RawHtml): Island<Record<string, unknown>, MergeState<MergeState<MergeState<Record<string, never>, "loading", boolean>, "error", string>, "items", string[]>> render (({ state: IslandState<MergeState<MergeState<MergeState<Record<string, never>, "loading", boolean>, "error", string>, "items", string[]>> state }) => {
if (state: IslandState<MergeState<MergeState<MergeState<Record<string, never>, "loading", boolean>, "error", string>, "items", string[]>> state .loading: MarkedSignalAccessor
() => boolean (+1 overload)
loading ()) return const html: (strings: TemplateStringsArray, ...values: unknown[]) => RawHtml html `<p>Loading…</p>`;
if (state: IslandState<MergeState<MergeState<MergeState<Record<string, never>, "loading", boolean>, "error", string>, "items", string[]>> state .error: MarkedSignalAccessor
() => string (+1 overload)
error ()) return const html: (strings: TemplateStringsArray, ...values: unknown[]) => RawHtml html `<p>Error: ${state: IslandState<MergeState<MergeState<MergeState<Record<string, never>, "loading", boolean>, "error", string>, "items", string[]>> state .error: SignalAccessor<string> error }</p>`;
return const html: (strings: TemplateStringsArray, ...values: unknown[]) => RawHtml html `
<ul>
${state: IslandState<MergeState<MergeState<MergeState<Record<string, never>, "loading", boolean>, "error", string>, "items", string[]>> state .items: MarkedSignalAccessor
() => string[] (+1 overload)
items ().Array<string>.map<RawHtml>(callbackfn: (value: string, index: number, array: string[]) => RawHtml, thisArg?: any): RawHtml[]Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value. map ((item: string item ) => const html: (strings: TemplateStringsArray, ...values: unknown[]) => RawHtml html `<li>${item: string item }</li>`)}
</ul>
`;
});#List rendering
Arrays of html\`` results are joined without commas. This is the canonical list rendering pattern:
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 List: Island<Record<string, unknown>, MergeState<Record<string, never>, "fruits", string[]>> List = 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<string[], "fruits">(key: "fruits", init?: StateInit<Record<string, unknown>, string[]> | undefined): IlhaBuilder<Record<string, unknown>, MergeState<Record<string, never>, "fruits", string[]>, Record<string, never>> state ("fruits", ["apple", "banana", "cherry"]).IlhaBuilder<Record<string, unknown>, MergeState<Record<string, never>, "fruits", string[]>, Record<string, never>>.render(fn: (ctx: RenderContext<Record<string, unknown>, MergeState<Record<string, never>, "fruits", string[]>, Record<string, never>>) => string | RawHtml): Island<Record<string, unknown>, MergeState<Record<string, never>, "fruits", string[]>> render (
({ state: IslandState<MergeState<Record<string, never>, "fruits", string[]>> state }) => const html: (strings: TemplateStringsArray, ...values: unknown[]) => RawHtml html `
<ul>
${state: IslandState<MergeState<Record<string, never>, "fruits", string[]>> state .fruits: MarkedSignalAccessor
() => string[] (+1 overload)
fruits ().Array<string>.map<RawHtml>(callbackfn: (value: string, index: number, array: string[]) => RawHtml, thisArg?: any): RawHtml[]Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value. map ((fruit: string fruit ) => const html: (strings: TemplateStringsArray, ...values: unknown[]) => RawHtml html `<li>${fruit: string fruit }</li>`)}
</ul>
`,
);#Async rendering
If the island uses async .derived() values, calling the island as a function awaits all of them before rendering:
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 from "ilha";
const const Island: Island<Record<string, unknown>, Record<string, never>> Island = 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>>.derived<"user", any>(key: "user", fn: DerivedFn<Record<string, unknown>, Record<string, never>, any>): IlhaBuilder<Record<string, unknown>, Record<string, never>, Record<string, never> & Record<"user", any>> derived ("user", async () => {
const const res: Response res = await function fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response> fetch ("/api/user");
return const res: Response res .Body.json(): Promise<any> json ();
})
.IlhaBuilder<Record<string, unknown>, Record<string, never>, Record<string, never> & Record<"user", any>>.render(fn: (ctx: RenderContext<Record<string, unknown>, Record<string, never>, Record<string, never> & Record<"user", any>>) => string | RawHtml): Island<Record<string, unknown>, Record<string, never>> render (({ derived: IslandDerived<Record<string, never> & Record<"user", any>> derived }) => {
if (derived: IslandDerived<Record<string, never> & Record<"user", any>> derived .user: DerivedValue<any> user .DerivedValue<any>.loading: boolean loading ) return `<p>Loading…</p>`;
return `<p>${derived: IslandDerived<Record<string, never> & Record<"user", any>> derived .user: DerivedValue<any> user .DerivedValue<any>.value: any value ?.name}</p>`;
});
// Async — waits for derived values
const const html: string html = await const Island: Island
(props?: Partial<Record<string, unknown>> | undefined) => string | Promise<string>
Island ();
// Sync — derived renders in loading state
const const html2: string html2 = const Island: Island<Record<string, unknown>, Record<string, never>> Island .Island<Record<string, unknown>, Record<string, never>>.toString(props?: Partial<Record<string, unknown>> | undefined): string toString ();#What .render() returns
Calling .render() produces an Island object with three methods:
island(props?) // renders to string, async if derived values are async
island.toString(props?) // always renders synchronously
island.mount(host, props?) // mounts into a DOM element, returns unmount()
island.hydratable(props, options) // renders wrapped in hydration container#Notes
.render()must be called exactly once and always last in the chain.- The render function runs on every re-render triggered by a signal change. Keep it fast and free of side effects — use
.effect()or.onMount()for side effects instead. - During SSR the render function runs synchronously. Avoid browser-only APIs (
window,document) at the top level of the render function. - The render function does not receive
host— if you need the host element, use.onMount()or.effect().