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().
ilha ships its own JSX runtime. For TypeScript projects, set jsxImportSource to "ilha":
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "ilha"
}
}
For individual examples or files, you can use a file pragma instead:
import const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha from "ilha";
const const Hello: Island<Record<string, unknown>, Record<never, never>>Hello = const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>.render(fn: (ctx: RenderContext<Record<string, unknown>, Record<never, never>, Record<never, never>>) => string | RawHtml): Island<Record<string, unknown>, Record<never, never>>render(() => <IntrinsicElements[string]: anyp>Hello, ilha!IntrinsicElements[string]: anyp>);
JSX is the recommended authoring style for islands. The lower-level html`` helper is still available and is useful for no-build environments or places where you do not want JSX tooling. For example, you can drop a "userInput = '';
<IntrinsicElements[string]: anyp>{const userInput: ""userInput}IntrinsicElements[string]: anyp>;
// →
null and undefined render as empty strings. Arrays are flattened and rendered without commas.
<IntrinsicElements[string]: anyp>{["a", null, var undefinedundefined, "b"]}IntrinsicElements[string]: anyp>
// → ab
Use raw() only for trusted markup you control:
import { const raw: (value: string) => RawHtmlraw } from "ilha";
const const icon: ""icon = ``;
<IntrinsicElements[string]: anybutton>{function raw(value: string): RawHtmlraw(const icon: ""icon)} SaveIntrinsicElements[string]: anybutton>;
Signals in JSX
State entries are signal accessors. You can call them explicitly:
import const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha from "ilha";
const const Counter: Island<Record<string, unknown>, MergeState<Record<never, never>, "count", number>>Counter = const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha
.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>.state<number, "count">(key: "count", init?: StateInit<Record<string, unknown>, number> | undefined): IlhaBuilder<Record<string, unknown>, MergeState<Record<never, never>, "count", number>, Record<never, never>>state("count", 0)
.IlhaBuilder<Record<string, unknown>, MergeState<Record<never, never>, "count", number>, Record<never, never>>.render(fn: (ctx: RenderContext<Record<string, unknown>, MergeState<Record<never, never>, "count", number>, Record<never, never>>) => string | RawHtml): Island<Record<string, unknown>, MergeState<Record<never, never>, "count", number>>render(({ state: IslandState<MergeState<Record<never, never>, "count", number>>state }) => <IntrinsicElements[string]: anyp>{state: IslandState<MergeState<Record<never, never>, "count", number>>state.count: MarkedSignalAccessor
() => number (+1 overload)
count()}IntrinsicElements[string]: anyp>);
You can also pass the accessor itself as a child; ilha will read it and escape the value:
import const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha from "ilha";
const const Label: Island<Record<string, unknown>, MergeState<Record<never, never>, "label", string>>Label = const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha
.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>.state<string, "label">(key: "label", init?: StateInit<Record<string, unknown>, string> | undefined): IlhaBuilder<Record<string, unknown>, MergeState<Record<never, never>, "label", string>, Record<never, never>>state("label", "safe")
.IlhaBuilder<Record<string, unknown>, MergeState<Record<never, never>, "label", string>, Record<never, never>>.render(fn: (ctx: RenderContext<Record<string, unknown>, MergeState<Record<never, never>, "label", string>, Record<never, never>>) => string | RawHtml): Island<Record<string, unknown>, MergeState<Record<never, never>, "label", string>>render(({ state: IslandState<MergeState<Record<never, never>, "label", string>>state }) => <IntrinsicElements[string]: anyp>{state: IslandState<MergeState<Record<never, never>, "label", string>>state.label: SignalAccessor<string>label}IntrinsicElements[string]: anyp>);
// → safe
Attributes
JSX attributes are escaped. Boolean true renders as a boolean attribute, while false, null, and undefined omit the attribute.
<IntrinsicElements[string]: anybutton disabled: booleandisabled={true} title: stringtitle={'a"b'}>
Save
IntrinsicElements[string]: anybutton>
// →
Use class normally. className and htmlFor are also accepted and normalized to class and for.
<IntrinsicElements[string]: anylabel htmlFor?: string | undefinedhtmlFor="email" class?: string | unknown[] | Record<string, boolean> | undefinedclass="field">
Email
IntrinsicElements[string]: anylabel>
class also accepts arrays and object maps:
const const active: trueactive = true;
<IntrinsicElements[string]: anydiv class?: string | unknown[] | Record<string, boolean> | undefinedclass={["tab", const active: trueactive && "is-active"]}>TabIntrinsicElements[string]: anydiv>;
<IntrinsicElements[string]: anydiv class?: string | unknown[] | Record<string, boolean> | undefinedclass={{ tab: truetab: true, "is-active": const active: trueactive }}>TabIntrinsicElements[string]: anydiv>;
Function event props such as onClick={...} are intentionally omitted from the generated HTML. Use .on() for behavior instead.
Events and re-rendering
Attach DOM events with .on(), then render JSX from .render():
import const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha from "ilha";
const const Counter: Island<Record<string, unknown>, MergeState<Record<never, never>, "count", number>>Counter = const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha
.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>.state<number, "count">(key: "count", init?: StateInit<Record<string, unknown>, number> | undefined): IlhaBuilder<Record<string, unknown>, MergeState<Record<never, never>, "count", number>, Record<never, never>>state("count", 0)
.IlhaBuilder<Record<string, unknown>, MergeState<Record<never, never>, "count", number>, Record<never, never>>.on<"button@click">(selectorOrCombined: "button@click", handler: (ctx: HandlerContextFor<Record<string, unknown>, MergeState<Record<never, never>, "count", number>, "click", Record<never, never>>) => void | Promise<void>): IlhaBuilder<Record<string, unknown>, MergeState<Record<never, never>, "count", number>, Record<never, never>>on("button@click", ({ state: IslandState<MergeState<Record<never, never>, "count", number>>state }) => {
state: IslandState<MergeState<Record<never, never>, "count", number>>state.count: MarkedSignalAccessor
(value: number) => void (+1 overload)
count(state: IslandState<MergeState<Record<never, never>, "count", number>>state.count: MarkedSignalAccessor
() => number (+1 overload)
count() + 1);
})
.IlhaBuilder<Record<string, unknown>, MergeState<Record<never, never>, "count", number>, Record<never, never>>.render(fn: (ctx: RenderContext<Record<string, unknown>, MergeState<Record<never, never>, "count", number>, Record<never, never>>) => string | RawHtml): Island<Record<string, unknown>, MergeState<Record<never, never>, "count", number>>render(({ state: IslandState<MergeState<Record<never, never>, "count", number>>state }) => (
<IntrinsicElements[string]: anydiv>
<IntrinsicElements[string]: anyp>Count: {state: IslandState<MergeState<Record<never, never>, "count", number>>state.count: MarkedSignalAccessor
() => number (+1 overload)
count()}IntrinsicElements[string]: anyp>
<IntrinsicElements[string]: anybutton type: stringtype="button">+IntrinsicElements[string]: anybutton>
IntrinsicElements[string]: anydiv>
));
When state.count changes, only this island re-renders and morphs its host DOM.
Conditional rendering
Use normal JavaScript control flow and ternaries:
import const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha from "ilha";
const const Island: Island<Record<string, unknown>, MergeState<MergeState<MergeState<Record<never, never>, "loading", boolean>, "error", string>, "items", string[]>>Island = const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha
.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>.state<boolean, "loading">(key: "loading", init?: StateInit<Record<string, unknown>, boolean> | undefined): IlhaBuilder<Record<string, unknown>, MergeState<Record<never, never>, "loading", boolean>, Record<never, never>>state("loading", false)
.IlhaBuilder<Record<string, unknown>, MergeState<Record<never, never>, "loading", boolean>, Record<never, never>>.state<string, "error">(key: "error", init?: StateInit<Record<string, unknown>, string> | undefined): IlhaBuilder<Record<string, unknown>, MergeState<MergeState<Record<never, never>, "loading", boolean>, "error", string>, Record<never, never>>state("error", "")
.IlhaBuilder<Record<string, unknown>, MergeState<MergeState<Record<never, never>, "loading", boolean>, "error", string>, Record<never, never>>.state<string[], "items">(key: "items", init?: StateInit<Record<string, unknown>, string[]> | undefined): IlhaBuilder<Record<string, unknown>, MergeState<MergeState<MergeState<Record<never, never>, "loading", boolean>, "error", string>, "items", string[]>, Record<never, never>>state("items", [] as string[])
.IlhaBuilder<Record<string, unknown>, MergeState<MergeState<MergeState<Record<never, never>, "loading", boolean>, "error", string>, "items", string[]>, Record<...>>.render(fn: (ctx: RenderContext<Record<string, unknown>, MergeState<MergeState<MergeState<Record<never, never>, "loading", boolean>, "error", string>, "items", string[]>, Record<never, never>>) => string | RawHtml): Island<Record<string, unknown>, MergeState<MergeState<MergeState<Record<never, never>, "loading", boolean>, "error", string>, "items", string[]>>render(({ state: IslandState<MergeState<MergeState<MergeState<Record<never, never>, "loading", boolean>, "error", string>, "items", string[]>>state }) => {
if (state: IslandState<MergeState<MergeState<MergeState<Record<never, never>, "loading", boolean>, "error", string>, "items", string[]>>state.loading: MarkedSignalAccessor
() => boolean (+1 overload)
loading()) return <IntrinsicElements[string]: anyp>Loading…IntrinsicElements[string]: anyp>;
if (state: IslandState<MergeState<MergeState<MergeState<Record<never, never>, "loading", boolean>, "error", string>, "items", string[]>>state.error: MarkedSignalAccessor
() => string (+1 overload)
error()) return <IntrinsicElements[string]: anyp>Error: {state: IslandState<MergeState<MergeState<MergeState<Record<never, never>, "loading", boolean>, "error", string>, "items", string[]>>state.error: MarkedSignalAccessor
() => string (+1 overload)
error()}IntrinsicElements[string]: anyp>;
return (
<IntrinsicElements[string]: anyul>
{state: IslandState<MergeState<MergeState<MergeState<Record<never, never>, "loading", boolean>, "error", string>, "items", string[]>>state.items: MarkedSignalAccessor
() => string[] (+1 overload)
items().Array<string>.map<JSX.Element>(callbackfn: (value: string, index: number, array: string[]) => JSX.Element, thisArg?: any): JSX.Element[]Calls a defined callback function on each element of an array, and returns an array that contains the results.map((item: stringitem) => (
<IntrinsicElements[string]: anyli>{item: stringitem}IntrinsicElements[string]: anyli>
))}
IntrinsicElements[string]: anyul>
);
});
List rendering
Arrays of JSX results are joined without commas. Do not call .join(""):
import const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha from "ilha";
const const List: Island<Record<string, unknown>, MergeState<Record<never, never>, "fruits", string[]>>List = const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha
.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>.state<string[], "fruits">(key: "fruits", init?: StateInit<Record<string, unknown>, string[]> | undefined): IlhaBuilder<Record<string, unknown>, MergeState<Record<never, never>, "fruits", string[]>, Record<never, never>>state("fruits", ["apple", "banana", "cherry"])
.IlhaBuilder<Record<string, unknown>, MergeState<Record<never, never>, "fruits", string[]>, Record<never, never>>.render(fn: (ctx: RenderContext<Record<string, unknown>, MergeState<Record<never, never>, "fruits", string[]>, Record<never, never>>) => string | RawHtml): Island<Record<string, unknown>, MergeState<Record<never, never>, "fruits", string[]>>render(({ state: IslandState<MergeState<Record<never, never>, "fruits", string[]>>state }) => (
<IntrinsicElements[string]: anyul>
{state: IslandState<MergeState<Record<never, never>, "fruits", string[]>>state.fruits: MarkedSignalAccessor
() => string[] (+1 overload)
fruits().Array<string>.map<JSX.Element>(callbackfn: (value: string, index: number, array: string[]) => JSX.Element, thisArg?: any): JSX.Element[]Calls a defined callback function on each element of an array, and returns an array that contains the results.map((fruit: stringfruit) => (
<IntrinsicElements[string]: anyli>{fruit: stringfruit}IntrinsicElements[string]: anyli>
))}
IntrinsicElements[string]: anyul>
));
Each item is escaped independently, so mapped user content stays safe.
Fragments
Use fragments when a render function needs to return siblings without an extra wrapper:
import const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha from "ilha";
const const Form: Island<Record<string, unknown>, Record<never, never>>Form = const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>.render(fn: (ctx: RenderContext<Record<string, unknown>, Record<never, never>, Record<never, never>>) => string | RawHtml): Island<Record<string, unknown>, Record<never, never>>render(() => (
<>
<IntrinsicElements[string]: anyinput name: stringname="email" />
<IntrinsicElements[string]: anybutton>SubmitIntrinsicElements[string]: anybutton>
>
));
Child islands
Render child islands as JSX components:
import const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha from "ilha";
const const Child: Island<Record<string, unknown>, MergeState<Record<never, never>, "count", number>>Child = const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha
.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>.state<number, "count">(key: "count", init?: StateInit<Record<string, unknown>, number> | undefined): IlhaBuilder<Record<string, unknown>, MergeState<Record<never, never>, "count", number>, Record<never, never>>state("count", 0)
.IlhaBuilder<Record<string, unknown>, MergeState<Record<never, never>, "count", number>, Record<never, never>>.render(fn: (ctx: RenderContext<Record<string, unknown>, MergeState<Record<never, never>, "count", number>, Record<never, never>>) => string | RawHtml): Island<Record<string, unknown>, MergeState<Record<never, never>, "count", number>>render(({ state: IslandState<MergeState<Record<never, never>, "count", number>>state }) => <IntrinsicElements[string]: anybutton>{state: IslandState<MergeState<Record<never, never>, "count", number>>state.count: MarkedSignalAccessor
() => number (+1 overload)
count()}IntrinsicElements[string]: anybutton>);
const const Parent: Island<Record<string, unknown>, Record<never, never>>Parent = const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>.render(fn: (ctx: RenderContext<Record<string, unknown>, Record<never, never>, Record<never, never>>) => string | RawHtml): Island<Record<string, unknown>, Record<never, never>>render(() => (
<IntrinsicElements[string]: anysection>
<IntrinsicElements[string]: anyh1>ParentIntrinsicElements[string]: anyh1>
<const Child: Island<Record<string, unknown>, MergeState<Record<never, never>, "count", number>>Child />
IntrinsicElements[string]: anysection>
));
Child islands render inline during SSR and mount independently on the client. A state change in the child does not re-render the parent.
Pass props with normal JSX attributes:
import const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha from "ilha";
import { import zz } from "zod";
const const Badge: Island<{
label: string;
} & Record<string, unknown>, Record<never, never>>
Badge = const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha
.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>.input<z.ZodObject<{
label: z.ZodString;
}, "strip", z.ZodTypeAny, {
label: string;
}, {
label: string;
}>>(schema: z.ZodObject<{
label: z.ZodString;
}, "strip", z.ZodTypeAny, {
label: string;
}, {
label: string;
}>): IlhaBuilder<{
label: string;
} & Record<string, unknown>, Record<never, never>, Record<never, never>> (+1 overload)
input(import zz.object<{
label: z.ZodString;
}>(shape: {
label: z.ZodString;
}, params?: z.RawCreateParams): z.ZodObject<{
label: z.ZodString;
}, "strip", z.ZodTypeAny, {
label: string;
}, {
label: string;
}>
export object
object({ label: z.ZodStringlabel: import zz.function string(params?: z.RawCreateParams & {
coerce?: true;
}): z.ZodString
export string
string() }))
.IlhaBuilder<{ label: string; } & Record<string, unknown>, Record<never, never>, Record<never, never>>.render(fn: (ctx: RenderContext<{
label: string;
} & Record<string, unknown>, Record<never, never>, Record<never, never>>) => string | RawHtml): Island<{
label: string;
} & Record<string, unknown>, Record<never, never>>
render(({ input: {
label: string;
} & Record<string, unknown>
input }) => <IntrinsicElements[string]: anystrong>{input: {
label: string;
} & Record<string, unknown>
input.label: stringlabel}IntrinsicElements[string]: anystrong>);
const const Page: Island<Record<string, unknown>, Record<never, never>>Page = const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>.render(fn: (ctx: RenderContext<Record<string, unknown>, Record<never, never>, Record<never, never>>) => string | RawHtml): Island<Record<string, unknown>, Record<never, never>>render(() => <const Badge: Island<{
label: string;
} & Record<string, unknown>, Record<never, never>>
Badge label?: string | undefinedlabel="New" />);
For keyed child islands in lists, create a keyed component before rendering it:
import const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha from "ilha";
import { import zz } from "zod";
const const items: {
id: string;
label: string;
}[]
items = [
{ id: stringid: "a", label: stringlabel: "A" },
{ id: stringid: "b", label: stringlabel: "B" },
];
const const Item: Island<{
label: string;
} & Record<string, unknown>, Record<never, never>>
Item = const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha
.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>.input<z.ZodObject<{
label: z.ZodString;
}, "strip", z.ZodTypeAny, {
label: string;
}, {
label: string;
}>>(schema: z.ZodObject<{
label: z.ZodString;
}, "strip", z.ZodTypeAny, {
label: string;
}, {
label: string;
}>): IlhaBuilder<{
label: string;
} & Record<string, unknown>, Record<never, never>, Record<never, never>> (+1 overload)
input(import zz.object<{
label: z.ZodString;
}>(shape: {
label: z.ZodString;
}, params?: z.RawCreateParams): z.ZodObject<{
label: z.ZodString;
}, "strip", z.ZodTypeAny, {
label: string;
}, {
label: string;
}>
export object
object({ label: z.ZodStringlabel: import zz.function string(params?: z.RawCreateParams & {
coerce?: true;
}): z.ZodString
export string
string() }))
.IlhaBuilder<{ label: string; } & Record<string, unknown>, Record<never, never>, Record<never, never>>.render(fn: (ctx: RenderContext<{
label: string;
} & Record<string, unknown>, Record<never, never>, Record<never, never>>) => string | RawHtml): Island<{
label: string;
} & Record<string, unknown>, Record<never, never>>
render(({ input: {
label: string;
} & Record<string, unknown>
input }) => <IntrinsicElements[string]: anyli>{input: {
label: string;
} & Record<string, unknown>
input.label: stringlabel}IntrinsicElements[string]: anyli>);
const const List: Island<Record<string, unknown>, Record<never, never>>List = const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>.render(fn: (ctx: RenderContext<Record<string, unknown>, Record<never, never>, Record<never, never>>) => string | RawHtml): Island<Record<string, unknown>, Record<never, never>>render(() => (
<IntrinsicElements[string]: anyul>
{const items: {
id: string;
label: string;
}[]
items.Array<{ id: string; label: string; }>.map<JSX.Element>(callbackfn: (value: {
id: string;
label: string;
}, index: number, array: {
id: string;
label: string;
}[]) => JSX.Element, thisArg?: any): JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.map((item: {
id: string;
label: string;
}
item) => {
const const KeyedItem: KeyedIsland<{
label: string;
} & Record<string, unknown>>
KeyedItem = const Item: Island<{
label: string;
} & Record<string, unknown>, Record<never, never>>
Item.Island<{ label: string; } & Record<string, unknown>, Record<never, never>>.key(key: string): KeyedIsland<{
label: string;
} & Record<string, unknown>>
key(item: {
id: string;
label: string;
}
item.id: stringid);
return <const KeyedItem: KeyedIsland<{
label: string;
} & Record<string, unknown>>
KeyedItem label?: string | undefinedlabel={item: {
id: string;
label: string;
}
item.label: stringlabel} />;
})}
IntrinsicElements[string]: anyul>
));
Slot wrapper — .as(tag)
Embedded child islands are wrapped in a host element so ilha can hydrate and morph them independently of the parent. By default that wrapper is a with a data-ilha-slot attribute:
…child markup…
Call .as(tag) on the child island builder (anywhere before .render()) to use a different HTML tag — for valid structure ( inside ), semantics, or styling:
import const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha from "ilha";
const const Age: Island<Record<string, unknown>, MergeState<Record<never, never>, "age", number>>Age = const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha
.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>.as<"span">(tag: "span"): IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>as("span")
.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>.state<number, "age">(key: "age", init?: StateInit<Record<string, unknown>, number> | undefined): IlhaBuilder<Record<string, unknown>, MergeState<Record<never, never>, "age", number>, Record<never, never>>state("age", 0)
.IlhaBuilder<Record<string, unknown>, MergeState<Record<never, never>, "age", number>, Record<never, never>>.render(fn: (ctx: RenderContext<Record<string, unknown>, MergeState<Record<never, never>, "age", number>, Record<never, never>>) => string | RawHtml): Island<Record<string, unknown>, MergeState<Record<never, never>, "age", number>>render(({ state: IslandState<MergeState<Record<never, never>, "age", number>>state }) => <>{state: IslandState<MergeState<Record<never, never>, "age", number>>state.age: MarkedSignalAccessor
() => number (+1 overload)
age()}>);
const const Parent: Island<Record<string, unknown>, Record<never, never>>Parent = const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>.render(fn: (ctx: RenderContext<Record<string, unknown>, Record<never, never>, Record<never, never>>) => string | RawHtml): Island<Record<string, unknown>, Record<never, never>>render(() => <IntrinsicElements[string]: anyp>Age: {const Age: Island<Record<string, unknown>, MergeState<Record<never, never>, "age", number>>Age}IntrinsicElements[string]: anyp>);
// → Age: 0
import const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha from "ilha";
const const Row: Island<{
label: string;
}, Record<never, never>>
Row = const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha
.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>.as<"li">(tag: "li"): IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>as("li")
.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>.input<{
label: string;
}>(): IlhaBuilder<{
label: string;
}, Record<never, never>, Record<never, never>> (+1 overload)
input<{ label: stringlabel: string }>()
.IlhaBuilder<{ label: string; }, Record<never, never>, Record<never, never>>.render(fn: (ctx: RenderContext<{
label: string;
}, Record<never, never>, Record<never, never>>) => string | RawHtml): Island<{
label: string;
}, Record<never, never>>
render(({ input: {
label: string;
}
input }) => <>{input: {
label: string;
}
input.label: stringlabel}>);
const const List: Island<Record<string, unknown>, Record<never, never>>List = const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>.render(fn: (ctx: RenderContext<Record<string, unknown>, Record<never, never>, Record<never, never>>) => string | RawHtml): Island<Record<string, unknown>, Record<never, never>>render(() => (
<IntrinsicElements[string]: anyul>
{["a", "b"].Array<string>.map<JSX.Element>(callbackfn: (value: string, index: number, array: string[]) => JSX.Element, thisArg?: any): JSX.Element[]Calls a defined callback function on each element of an array, and returns an array that contains the results.map((label: stringlabel) => (
<const Row: Island<{
label: string;
}, Record<never, never>>
Row JSX.IntrinsicAttributes.key?: string | number | undefinedkey={label: stringlabel} label?: string | undefinedlabel={label: stringlabel} />
))}
IntrinsicElements[string]: anyul>
));
For list items that keep local state across reorders, combine .as("li") with .key(id) on the child (see keyed child islands above):
import const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha from "ilha";
const const Item: Island<{
label: string;
}, MergeState<Record<never, never>, "n", number>>
Item = const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha
.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>.as<"li">(tag: "li"): IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>as("li")
.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>.input<{
label: string;
}>(): IlhaBuilder<{
label: string;
}, Record<never, never>, Record<never, never>> (+1 overload)
input<{ label: stringlabel: string }>()
.IlhaBuilder<{ label: string; }, Record<never, never>, Record<never, never>>.state<number, "n">(key: "n", init?: StateInit<{
label: string;
}, number> | undefined): IlhaBuilder<{
label: string;
}, MergeState<Record<never, never>, "n", number>, Record<never, never>>
state("n", 0)
.IlhaBuilder<{ label: string; }, MergeState<Record<never, never>, "n", number>, Record<never, never>>.on<"[data-bump]@click">(selectorOrCombined: "[data-bump]@click", handler: (ctx: HandlerContextFor<{
label: string;
}, MergeState<Record<never, never>, "n", number>, "click", Record<never, never>>) => void | Promise<void>): IlhaBuilder<{
label: string;
}, MergeState<Record<never, never>, "n", number>, Record<never, never>>
on("[data-bump]@click", ({ state: IslandState<MergeState<Record<never, never>, "n", number>>state }) => {
state: IslandState<MergeState<Record<never, never>, "n", number>>state.n: MarkedSignalAccessor
(value: number) => void (+1 overload)
n(state: IslandState<MergeState<Record<never, never>, "n", number>>state.n: MarkedSignalAccessor
() => number (+1 overload)
n() + 1);
})
.IlhaBuilder<{ label: string; }, MergeState<Record<never, never>, "n", number>, Record<never, never>>.render(fn: (ctx: RenderContext<{
label: string;
}, MergeState<Record<never, never>, "n", number>, Record<never, never>>) => string | RawHtml): Island<{
label: string;
}, MergeState<Record<never, never>, "n", number>>
render(({ input: {
label: string;
}
input, state: IslandState<MergeState<Record<never, never>, "n", number>>state }) => (
<>
{input: {
label: string;
}
input.label: stringlabel}:{state: IslandState<MergeState<Record<never, never>, "n", number>>state.n: MarkedSignalAccessor
() => number (+1 overload)
n()}
<IntrinsicElements[string]: anybutton type: stringtype="button" data-bump: truedata-bump>
+
IntrinsicElements[string]: anybutton>
>
));
const const List: Island<Record<string, unknown>, MergeState<Record<never, never>, "order", string[]>>List = const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha
.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>.state<string[], "order">(key: "order", init?: StateInit<Record<string, unknown>, string[]> | undefined): IlhaBuilder<Record<string, unknown>, MergeState<Record<never, never>, "order", string[]>, Record<never, never>>state("order", ["a", "b"] as string[])
.IlhaBuilder<Record<string, unknown>, MergeState<Record<never, never>, "order", string[]>, Record<never, never>>.render(fn: (ctx: RenderContext<Record<string, unknown>, MergeState<Record<never, never>, "order", string[]>, Record<never, never>>) => string | RawHtml): Island<Record<string, unknown>, MergeState<Record<never, never>, "order", string[]>>render(({ state: IslandState<MergeState<Record<never, never>, "order", string[]>>state }) => (
<IntrinsicElements[string]: anyul>
{state: IslandState<MergeState<Record<never, never>, "order", string[]>>state.order: MarkedSignalAccessor
() => string[] (+1 overload)
order().Array<string>.map<JSX.Element>(callbackfn: (value: string, index: number, array: string[]) => JSX.Element, thisArg?: any): JSX.Element[]Calls a defined callback function on each element of an array, and returns an array that contains the results.map((k: stringk) => {
const const Keyed: KeyedIsland<{
label: string;
}>
Keyed = const Item: Island<{
label: string;
}, MergeState<Record<never, never>, "n", number>>
Item.Island<{ label: string; }, MergeState<Record<never, never>, "n", number>>.key(key: string): KeyedIsland<{
label: string;
}>
key(k: stringk);
return <const Keyed: KeyedIsland<{
label: string;
}>
Keyed label?: string | undefinedlabel={k: stringk} />;
})}
IntrinsicElements[string]: anyul>
));
The tag must be a non-empty name matching ilha’s rule: start with an ASCII letter, then letters, digits, or hyphens (same idea as built-in tags like span, li, section — not arbitrary strings). Invalid names throw at builder time.
.as() on the ilha builder is only for child island slot wrappers. List helpers such as each() (for example from Quando) use a separate .as((item, index) => …) API for mapping items to JSX — not the same method.
Function components
Small JSX helper components can return JSX or strings. They receive an object even when no props are passed, so destructuring is safe:
function function EmptyState({ label, }: {
label?: string;
}): JSX.Element
EmptyState({
label: stringlabel = "Nothing here",
}: {
label?: string | undefinedlabel?: string;
}) {
return <IntrinsicElements[string]: anyp>{label: stringlabel}IntrinsicElements[string]: anyp>;
}
const const out: JSX.Elementout = <function EmptyState({ label, }: {
label?: string;
}): JSX.Element
EmptyState />;
For stateful, mountable UI, prefer an ilha island (ilha.render(...)) over a plain function component.
Template bindings
Inside JSX, use bind:property={signal} to create two-way bindings between form elements and signals. When the signal changes, the element updates. When the user interacts with the element, the signal updates.
import const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha from "ilha";
const const Name: Island<Record<string, unknown>, MergeState<Record<never, never>, "name", string>>Name = const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>.state<string, "name">(key: "name", init?: StateInit<Record<string, unknown>, string> | undefined): IlhaBuilder<Record<string, unknown>, MergeState<Record<never, never>, "name", string>, Record<never, never>>state("name", "Ada").IlhaBuilder<Record<string, unknown>, MergeState<Record<never, never>, "name", string>, Record<never, never>>.render(fn: (ctx: RenderContext<Record<string, unknown>, MergeState<Record<never, never>, "name", string>, Record<never, never>>) => string | RawHtml): Island<Record<string, unknown>, MergeState<Record<never, never>, "name", string>>render(({ state: IslandState<MergeState<Record<never, never>, "name", string>>state }) => (
<IntrinsicElements[string]: anydiv>
<IntrinsicElements[string]: anyinput bind:value: SignalAccessor<string>bind:bind:value: SignalAccessor<string>value={state: IslandState<MergeState<Record<never, never>, "name", string>>state.name: SignalAccessor<string>name} />
<IntrinsicElements[string]: anyp>Hello, {state: IslandState<MergeState<Record<never, never>, "name", string>>state.name: MarkedSignalAccessor
() => string (+1 overload)
name()}IntrinsicElements[string]: anyp>
IntrinsicElements[string]: anydiv>
));
Supported bindings
Binding Element Bound property Trigger event bind:value, , valueinputbind:valueAsNumbervalueAsNumberinputbind:valueAsDatevalueAsDateinputbind:checkedcheckedchangebind:group, checked / valuechangebind:openopentogglebind:filesfileschangebind:thisAny element element reference —
The element type is detected at runtime — no configuration needed.
Areia in nested child islands: use bind:checked={state.flag} on and bind:group={state.tab} on (recent areia mounts Switch.Root / Tabs.Root when bind props are present). Controlled checked + onCheckedChange or value + onValueChange still work.
Radio and checkbox groups
import const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha from "ilha";
const const Plan: Island<Record<string, unknown>, MergeState<Record<never, never>, "plan", string>>Plan = const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>.state<string, "plan">(key: "plan", init?: StateInit<Record<string, unknown>, string> | undefined): IlhaBuilder<Record<string, unknown>, MergeState<Record<never, never>, "plan", string>, Record<never, never>>state("plan", "pro").IlhaBuilder<Record<string, unknown>, MergeState<Record<never, never>, "plan", string>, Record<never, never>>.render(fn: (ctx: RenderContext<Record<string, unknown>, MergeState<Record<never, never>, "plan", string>, Record<never, never>>) => string | RawHtml): Island<Record<string, unknown>, MergeState<Record<never, never>, "plan", string>>render(({ state: IslandState<MergeState<Record<never, never>, "plan", string>>state }) => (
<>
<IntrinsicElements[string]: anyinput
type: stringtype="radio"
name: stringname="plan"
value: stringvalue="free"
bind:group: SignalAccessor<string>bind:bind:group: SignalAccessor<string>group={state: IslandState<MergeState<Record<never, never>, "plan", string>>state.plan: SignalAccessor<string>plan}
/>
<IntrinsicElements[string]: anyinput
type: stringtype="radio"
name: stringname="plan"
value: stringvalue="pro"
bind:group: SignalAccessor<string>bind:bind:group: SignalAccessor<string>group={state: IslandState<MergeState<Record<never, never>, "plan", string>>state.plan: SignalAccessor<string>plan}
/>
>
));
const const Tags: Island<Record<string, unknown>, MergeState<Record<never, never>, string, string[]>>Tags = const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha
.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>.state<string[], string>(key: string, init?: StateInit<Record<string, unknown>, string[]> | undefined): IlhaBuilder<Record<string, unknown>, MergeState<Record<never, never>, string, string[]>, Record<never, never>>state<string[]>("tags", ["ts"])
.IlhaBuilder<Record<string, unknown>, MergeState<Record<never, never>, string, string[]>, Record<never, never>>.render(fn: (ctx: RenderContext<Record<string, unknown>, MergeState<Record<never, never>, string, string[]>, Record<never, never>>) => string | RawHtml): Island<Record<string, unknown>, MergeState<Record<never, never>, string, string[]>>render(({ state: IslandState<MergeState<Record<never, never>, string, string[]>>state }) => (
<>
<IntrinsicElements[string]: anyinput
type: stringtype="checkbox"
name: stringname="tag"
value: stringvalue="js"
bind:group: SignalAccessor<string[]>bind:bind:group: SignalAccessor<string[]>group={state: IslandState<MergeState<Record<never, never>, string, string[]>>state.SignalAccessor<string[]>tags}
/>
<IntrinsicElements[string]: anyinput
type: stringtype="checkbox"
name: stringname="tag"
value: stringvalue="ts"
bind:group: SignalAccessor<string[]>bind:bind:group: SignalAccessor<string[]>group={state: IslandState<MergeState<Record<never, never>, string, string[]>>state.SignalAccessor<string[]>tags}
/>
<IntrinsicElements[string]: anyinput
type: stringtype="checkbox"
name: stringname="tag"
value: stringvalue="rust"
bind:group: SignalAccessor<string[]>bind:bind:group: SignalAccessor<string[]>group={state: IslandState<MergeState<Record<never, never>, string, string[]>>state.SignalAccessor<string[]>tags}
/>
>
));
Nested fields with .select()
When state holds an object or array, bind to a nested slice with .select() instead of replacing the whole value on every keystroke:
import const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha from "ilha";
const const Profile: Island<Record<string, unknown>, MergeState<Record<never, never>, "user", {
name: string;
role: string;
}>>
Profile = const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha
.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>.state<{
name: string;
role: string;
}, "user">(key: "user", init?: StateInit<Record<string, unknown>, {
name: string;
role: string;
}> | undefined): IlhaBuilder<Record<string, unknown>, MergeState<Record<never, never>, "user", {
name: string;
role: string;
}>, Record<never, never>>
state("user", { name: stringname: "Ada", role: stringrole: "dev" })
.IlhaBuilder<Record<string, unknown>, MergeState<Record<never, never>, "user", { name: string; role: string; }>, Record<never, never>>.render(fn: (ctx: RenderContext<Record<string, unknown>, MergeState<Record<never, never>, "user", {
name: string;
role: string;
}>, Record<never, never>>) => string | RawHtml): Island<Record<string, unknown>, MergeState<Record<never, never>, "user", {
name: string;
role: string;
}>>
render(({ state: IslandState<MergeState<Record<never, never>, "user", {
name: string;
role: string;
}>>
state }) => (
<IntrinsicElements[string]: anydiv>
<IntrinsicElements[string]: anyinput bind:value: MarkedSignalAccessor<string>bind:bind:value: MarkedSignalAccessor<string>value={state: IslandState<MergeState<Record<never, never>, "user", {
name: string;
role: string;
}>>
state.user: SignalAccessor<{
name: string;
role: string;
}>
user.MarkedSignalAccessor<{ name: string; role: string; }>.select<string>(selector: (state: {
name: string;
role: string;
}) => string): MarkedSignalAccessor<string>
select((u: {
name: string;
role: string;
}
u) => u: {
name: string;
role: string;
}
u.name: stringname)} />
<IntrinsicElements[string]: anyp>{state: IslandState<MergeState<Record<never, never>, "user", {
name: string;
role: string;
}>>
state.user: MarkedSignalAccessor
() => {
name: string;
role: string;
} (+1 overload)
user().name: stringname}IntrinsicElements[string]: anyp>
IntrinsicElements[string]: anydiv>
));
In a list, select the item field you need inside .map():
import const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha from "ilha";
const const Todos: Island<Record<string, unknown>, MergeState<Record<never, never>, "todos", {
text: string;
completed: boolean;
}[]>>
Todos = const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha
.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>.state<{
text: string;
completed: boolean;
}[], "todos">(key: "todos", init?: StateInit<Record<string, unknown>, {
text: string;
completed: boolean;
}[]> | undefined): IlhaBuilder<Record<string, unknown>, MergeState<Record<never, never>, "todos", {
text: string;
completed: boolean;
}[]>, Record<never, never>>
state("todos", [{ text: stringtext: "Learn ilha", completed: booleancompleted: false }])
.IlhaBuilder<Record<string, unknown>, MergeState<Record<never, never>, "todos", { text: string; completed: boolean; }[]>, Record<never, never>>.render(fn: (ctx: RenderContext<Record<string, unknown>, MergeState<Record<never, never>, "todos", {
text: string;
completed: boolean;
}[]>, Record<never, never>>) => string | RawHtml): Island<Record<string, unknown>, MergeState<Record<never, never>, "todos", {
text: string;
completed: boolean;
}[]>>
render(({ state: IslandState<MergeState<Record<never, never>, "todos", {
text: string;
completed: boolean;
}[]>>
state }) => (
<IntrinsicElements[string]: anyul>
{state: IslandState<MergeState<Record<never, never>, "todos", {
text: string;
completed: boolean;
}[]>>
state.todos: MarkedSignalAccessor
() => {
text: string;
completed: boolean;
}[] (+1 overload)
todos().Array<{ text: string; completed: boolean; }>.map<JSX.Element>(callbackfn: (value: {
text: string;
completed: boolean;
}, index: number, array: {
text: string;
completed: boolean;
}[]) => JSX.Element, thisArg?: any): JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.map((todo: {
text: string;
completed: boolean;
}
todo, index: numberindex) => (
<IntrinsicElements[string]: anyli JSX.IntrinsicAttributes.key?: string | number | undefinedkey={todo: {
text: string;
completed: boolean;
}
todo.text: stringtext}>
<IntrinsicElements[string]: anyinput
type: stringtype="checkbox"
bind:checked: MarkedSignalAccessor<boolean>bind:bind:checked: MarkedSignalAccessor<boolean>checked={state: IslandState<MergeState<Record<never, never>, "todos", {
text: string;
completed: boolean;
}[]>>
state.todos: SignalAccessor<{
text: string;
completed: boolean;
}[]>
todos.MarkedSignalAccessor<{ text: string; completed: boolean; }[]>.select<boolean>(selector: (state: {
text: string;
completed: boolean;
}[]) => boolean): MarkedSignalAccessor<boolean>
select(
(t: {
text: string;
completed: boolean;
}[]
t) => t: {
text: string;
completed: boolean;
}[]
t[index: numberindex].completed: booleancompleted,
)}
/>
{todo: {
text: string;
completed: boolean;
}
todo.text: stringtext}
IntrinsicElements[string]: anyli>
))}
IntrinsicElements[string]: anyul>
));
The selector must traverse nested state (for example (u) => u.name or (t) => t[i].completed). Writes update only that path — siblings and unrelated fields stay intact.
Element references
import const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha from "ilha";
const const Focus: Island<Record<string, unknown>, MergeState<Record<never, never>, "ref", HTMLInputElement | null>>Focus = const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha
.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>.state<HTMLInputElement | null, "ref">(key: "ref", init?: StateInit<Record<string, unknown>, HTMLInputElement | null> | undefined): IlhaBuilder<Record<string, unknown>, MergeState<Record<never, never>, "ref", HTMLInputElement | null>, Record<never, never>>state("ref", null as HTMLInputElement | null)
.IlhaBuilder<Record<string, unknown>, MergeState<Record<never, never>, "ref", HTMLInputElement | null>, Record<never, never>>.render(fn: (ctx: RenderContext<Record<string, unknown>, MergeState<Record<never, never>, "ref", HTMLInputElement | null>, Record<never, never>>) => string | RawHtml): Island<Record<string, unknown>, MergeState<Record<never, never>, "ref", HTMLInputElement | null>>render(({ state: IslandState<MergeState<Record<never, never>, "ref", HTMLInputElement | null>>state }) => <IntrinsicElements[string]: anyinput bind:this: SignalAccessor<HTMLInputElement | null>bind:bind:this: SignalAccessor<HTMLInputElement | null>this={state: IslandState<MergeState<Record<never, never>, "ref", HTMLInputElement | null>>state.ref: SignalAccessor<HTMLInputElement | null>ref} />);
External signals
Any signal created with signal() works as a binding target, including nested slices via .select():
import const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha, { function signal<T>(initial: T): SignalAccessor<T>Create a free-standing reactive signal that lives outside any island.
Useful for sharing state across islands without prop drilling, or for
binding form inputs to module-level state via the `bind:value=${signal}`
template syntax.
The returned accessor is a getter when called with no arguments and a
setter when called with one. Reading it inside a `.derived()`, `.effect()`,
or `.render()` automatically subscribes the surrounding reactive scope —
so when the signal changes, dependents re-run as if it were local state.signal } from "ilha";
const const username: SignalAccessor<string>username = signal<string>(initial: string): SignalAccessor<string>Create a free-standing reactive signal that lives outside any island.
Useful for sharing state across islands without prop drilling, or for
binding form inputs to module-level state via the `bind:value=${signal}`
template syntax.
The returned accessor is a getter when called with no arguments and a
setter when called with one. Reading it inside a `.derived()`, `.effect()`,
or `.render()` automatically subscribes the surrounding reactive scope —
so when the signal changes, dependents re-run as if it were local state.signal("");
const const LoginForm: Island<Record<string, unknown>, Record<never, never>>LoginForm = const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>.render(fn: (ctx: RenderContext<Record<string, unknown>, Record<never, never>, Record<never, never>>) => string | RawHtml): Island<Record<string, unknown>, Record<never, never>>render(() => (
<IntrinsicElements[string]: anyinput bind:value: SignalAccessor<string>bind:bind:value: SignalAccessor<string>value={const username: SignalAccessor<string>username} placeholder: stringplaceholder="Username" />
));
const const profile: SignalAccessor<{
user: {
name: string;
};
}>
profile = signal<{
user: {
name: string;
};
}>(initial: {
user: {
name: string;
};
}): SignalAccessor<{
user: {
name: string;
};
}>
Create a free-standing reactive signal that lives outside any island.
Useful for sharing state across islands without prop drilling, or for
binding form inputs to module-level state via the `bind:value=${signal}`
template syntax.
The returned accessor is a getter when called with no arguments and a
setter when called with one. Reading it inside a `.derived()`, `.effect()`,
or `.render()` automatically subscribes the surrounding reactive scope —
so when the signal changes, dependents re-run as if it were local state.signal({ user: {
name: string;
}
user: { name: stringname: "Ada" } });
const const Settings: Island<Record<string, unknown>, Record<never, never>>Settings = const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>.render(fn: (ctx: RenderContext<Record<string, unknown>, Record<never, never>, Record<never, never>>) => string | RawHtml): Island<Record<string, unknown>, Record<never, never>>render(() => (
<IntrinsicElements[string]: anyinput
bind:value: MarkedSignalAccessor<string>bind:bind:value: MarkedSignalAccessor<string>value={const profile: SignalAccessor<{
user: {
name: string;
};
}>
profile.MarkedSignalAccessor<{ user: { name: string; }; }>.select<string>(selector: (state: {
user: {
name: string;
};
}) => string): MarkedSignalAccessor<string>
select((p: {
user: {
name: string;
};
}
p) => p: {
user: {
name: string;
};
}
p.user: {
name: string;
}
user.name: stringname)}
placeholder: stringplaceholder="Name"
/>
));
html`` interop
JSX and html`` values compose. You can render an html`` result inside JSX, and JSX returns the same RawHtml shape:
import { const html: (strings: TemplateStringsArray, ...values: unknown[]) => RawHtmlhtml } from "ilha";
const const result: JSX.Elementresult = <IntrinsicElements[string]: anydiv>{const html: (strings: TemplateStringsArray, ...values: unknown[]) => RawHtmlhtml`${"safe"}`}IntrinsicElements[string]: anydiv>;
This is useful when incrementally migrating older html`` templates to JSX, or when sharing small trusted fragments between the two authoring styles.
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<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha from "ilha";
const const Island: Island<Record<string, unknown>, Record<never, never>>Island = const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, 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;
... 4 more ...;
onUncaughtError: typeof onUncaughtError;
}
ilha
.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never>>.derived<"user", any>(key: "user", fn: DerivedFn<Record<string, unknown>, Record<never, never>, any>): IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never> & Record<"user", any>>derived("user", async () => {
const const res: Responseres = await function fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>[MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/fetch)fetch("/api/user");
return const res: Responseres.Body.json(): Promise<any>[MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/json)json();
})
.IlhaBuilder<Record<string, unknown>, Record<never, never>, Record<never, never> & Record<"user", any>>.render(fn: (ctx: RenderContext<Record<string, unknown>, Record<never, never>, Record<never, never> & Record<"user", any>>) => string | RawHtml): Island<Record<string, unknown>, Record<never, never>>render(({ derived: IslandDerived<Record<never, never> & Record<"user", any>>derived }) => {
if (derived: IslandDerived<Record<never, never> & Record<"user", any>>derived.user: DerivedAccessor<any>user.loading: booleanloading) return <IntrinsicElements[string]: anyp>Loading…IntrinsicElements[string]: anyp>;
return <IntrinsicElements[string]: anyp>{derived: IslandDerived<Record<never, never> & Record<"user", any>>derived.user: () => any (+1 overload)user()?.name}IntrinsicElements[string]: anyp>;
});
// Async — waits for derived values
const const html: stringhtml = await const Island: Island
(props?: Partial<Record<string, unknown>> | undefined) => string | Promise<string>
Island();
// Sync — derived renders in loading state
const const html2: stringhtml2 = const Island: Island<Record<string, unknown>, Record<never, never>>Island.Island<Record<string, unknown>, Record<never, never>>.toString(props?: Partial<Record<string, unknown>> | undefined): stringtoString();
What .render() returns
Calling .render() produces an Island object with these 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.
- JSX output follows ilha's escaping rules; use
raw() only for trusted markup.
- Use
.on() for DOM events. JSX onClick-style function props are not how ilha attaches behavior.
- 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().