Skip to content

.onMount()

Register one-time setup functions that run after an island is mounted into the DOM.

Updated View as Markdown

Registers a function that runs once after the island is mounted into the DOM. Use it for one-time setup that needs access to the host element, such as initializing third-party libraries, measuring layout, or setting up manual DOM integrations.

Interactive Tutorial

Basic usage

Cleanup

Return a function to run cleanup on unmount:

import 
const ilha: RootBuilder & DirectIslandFactory & {
    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;
    ... 5 more ...;
    onUncaughtError: typeof onUncaughtError;
}
ilha
from "ilha";
const const Island: Island<RootInput, RootState>Island =
const ilha: RootBuilder & DirectIslandFactory & {
    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;
    ... 5 more ...;
    onUncaughtError: typeof onUncaughtError;
}
ilha
.IlhaBuilder<RootInput, RootState, RootDerived, RootActions>.onMount(fn: (ctx: OnMountContext<RootInput, RootState, RootDerived, RootActions>) => (() => void) | void): IlhaBuilder<RootInput, RootState, RootDerived, RootActions>onMount(({ host: Elementhost }) => { const const observer: ResizeObserverobserver = new var ResizeObserver: new (callback: ResizeObserverCallback) => ResizeObserver
The **`ResizeObserver`** interface reports changes to the dimensions of an Element's content or border box, or the bounding box of an SVGElement. [MDN Reference](https://developer.mozilla.org/docs/Web/API/ResizeObserver)
ResizeObserver
(() => {
var console: Consoleconsole.Console.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
("resized", host: Elementhost.Element.clientWidth: number
The **`clientWidth`** read-only property of the Element interface is zero for inline elements and elements with no CSS; otherwise, it's the inner width of an element in pixels. It includes padding but excludes borders, margins, and vertical scrollbars (if present). [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/clientWidth)
clientWidth
);
}); const observer: ResizeObserverobserver.ResizeObserver.observe(target: Element, options?: ResizeObserverOptions): void
The **`observe()`** method of the ResizeObserver interface starts observing the specified Element or SVGElement. [MDN Reference](https://developer.mozilla.org/docs/Web/API/ResizeObserver/observe)
observe
(host: Elementhost);
return () => const observer: ResizeObserverobserver.ResizeObserver.disconnect(): void
The **`disconnect()`** method of the ResizeObserver interface unobserves all observed Element or SVGElement targets. [MDN Reference](https://developer.mozilla.org/docs/Web/API/ResizeObserver/disconnect)
disconnect
();
}) .IlhaBuilder<RootInput, RootState, RootDerived, RootActions>.render(fn: (ctx: RenderContext<RootInput, RootState, RootDerived, RootActions>) => string | RawHtml): Island<RootInput, RootState>render(() => <"div": WithRawHtmlAttributeValues<JSX.HTMLAttributes<HTMLDivElement>>div>hello</"div": WithRawHtmlAttributeValues<JSX.HTMLAttributes<HTMLDivElement>>div>);

unmount() detaches the island’s listeners before it calls the cleanup function returned by .onMount().

Mount context

The function receives an OnMountContext:

{
  state: IslandState; // reactive state signals
  derived: IslandDerived; // current derived values
  action: IslandActions; // callable actions and their reactive status
  input: TInput; // resolved input props
  host: Element; // island root element
  hydrated: boolean; // true when mounted over SSR content
}

The hydrated flag tells you whether the island was activated over existing server-rendered HTML or freshly mounted into an empty element. This is useful when you want to skip an animation or initialization step for content that is already visible:

import 
const ilha: RootBuilder & DirectIslandFactory & {
    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;
    ... 5 more ...;
    onUncaughtError: typeof onUncaughtError;
}
ilha
from "ilha";
const const Island: Island<RootInput, RootState>Island =
const ilha: RootBuilder & DirectIslandFactory & {
    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;
    ... 5 more ...;
    onUncaughtError: typeof onUncaughtError;
}
ilha
.IlhaBuilder<RootInput, RootState, RootDerived, RootActions>.onMount(fn: (ctx: OnMountContext<RootInput, RootState, RootDerived, RootActions>) => (() => void) | void): IlhaBuilder<RootInput, RootState, RootDerived, RootActions>onMount(({ host: Elementhost, hydrated: booleanhydrated }) => { if (!hydrated: booleanhydrated) { host: Elementhost.Animatable.animate(keyframes: Keyframe[] | PropertyIndexedKeyframes | null, options?: number | KeyframeAnimationOptions): Animation
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/animate)
animate
([{ opacity: numberopacity: 0 }, { opacity: numberopacity: 1 }], 300);
} }) .IlhaBuilder<RootInput, RootState, RootDerived, RootActions>.render(fn: (ctx: RenderContext<RootInput, RootState, RootDerived, RootActions>) => string | RawHtml): Island<RootInput, RootState>render(() => <"div": WithRawHtmlAttributeValues<JSX.HTMLAttributes<HTMLDivElement>>div>content</"div": WithRawHtmlAttributeValues<JSX.HTMLAttributes<HTMLDivElement>>div>);

Initializing third-party libraries

.onMount() is the right place to hand off a DOM element to a library that manages its own rendering:

import 
const ilha: RootBuilder & DirectIslandFactory & {
    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;
    ... 5 more ...;
    onUncaughtError: typeof onUncaughtError;
}
ilha
from "ilha";
const
const Map: Island<{
    lat: number;
    lng: number;
}, Record<never, never>>
Map
=
const ilha: RootBuilder & DirectIslandFactory & {
    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;
    ... 5 more ...;
    onUncaughtError: typeof onUncaughtError;
}
ilha
.
IlhaBuilder<RootInput, RootState, RootDerived, RootActions>.input<{
    lat: number;
    lng: number;
}>(): IlhaBuilder<{
    lat: number;
    lng: number;
}, Record<never, never>, Record<never, never>, Record<never, never>> (+2 overloads)
input
<{ lat: numberlat: number; lng: numberlng: number }>()
.
IlhaBuilder<{ lat: number; lng: number; }, Record<never, never>, Record<never, never>, Record<never, never>>.onMount(fn: (ctx: OnMountContext<{
    lat: number;
    lng: number;
}, Record<never, never>, Record<never, never>, Record<never, never>>) => (() => void) | void): IlhaBuilder<{
    lat: number;
    lng: number;
}, Record<never, never>, Record<never, never>, Record<never, never>>
onMount
(({ host: Elementhost,
input: {
    lat: number;
    lng: number;
}
input
}) => {
const const map: anymap = new var window: Window & typeof globalThis
The **`window`** property of a Window object points to the window object itself. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/window)
window
.Window.MapLibrary: anyMapLibrary(host: Elementhost, {
center: number[]center: [
input: {
    lat: number;
    lng: number;
}
input
.lat: numberlat,
input: {
    lat: number;
    lng: number;
}
input
.lng: numberlng],
zoom: numberzoom: 12, }); return () => const map: anymap.destroy(); }) .
IlhaBuilder<{ lat: number; lng: number; }, Record<never, never>, Record<never, never>, Record<never, never>>.render(fn: (ctx: RenderContext<{
    lat: number;
    lng: number;
}, Record<never, never>, Record<never, never>, Record<never, never>>) => string | RawHtml): Island<{
    lat: number;
    lng: number;
}, Record<never, never>>
render
(() => <"div": WithRawHtmlAttributeValues<JSX.HTMLAttributes<HTMLDivElement>>div style?: string | RawHtml | StyleProps | undefinedstyle="height:400px"></"div": WithRawHtmlAttributeValues<JSX.HTMLAttributes<HTMLDivElement>>div>);

Multiple onMount hooks

Chain .onMount() as many times as needed. Each runs independently in the order it was declared:

import 
const ilha: RootBuilder & DirectIslandFactory & {
    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;
    ... 5 more ...;
    onUncaughtError: typeof onUncaughtError;
}
ilha
from "ilha";
const const Island: Island<RootInput, RootState>Island =
const ilha: RootBuilder & DirectIslandFactory & {
    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;
    ... 5 more ...;
    onUncaughtError: typeof onUncaughtError;
}
ilha
.IlhaBuilder<RootInput, RootState, RootDerived, RootActions>.onMount(fn: (ctx: OnMountContext<RootInput, RootState, RootDerived, RootActions>) => (() => void) | void): IlhaBuilder<RootInput, RootState, RootDerived, RootActions>onMount(({ host: Elementhost }) => { var console: Consoleconsole.Console.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
("first", host: Elementhost);
}) .IlhaBuilder<RootInput, RootState, RootDerived, RootActions>.onMount(fn: (ctx: OnMountContext<RootInput, RootState, RootDerived, RootActions>) => (() => void) | void): IlhaBuilder<RootInput, RootState, RootDerived, RootActions>onMount(({ state: IslandState<RootState>state }) => { var console: Consoleconsole.Console.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
("second");
}) .IlhaBuilder<RootInput, RootState, RootDerived, RootActions>.render(fn: (ctx: RenderContext<RootInput, RootState, RootDerived, RootActions>) => string | RawHtml): Island<RootInput, RootState>render(() => <"div": WithRawHtmlAttributeValues<JSX.HTMLAttributes<HTMLDivElement>>div>hello</"div": WithRawHtmlAttributeValues<JSX.HTMLAttributes<HTMLDivElement>>div>);

Skipping onMount during hydration

When using .hydratable() with snapshot: true, the skipOnMount option tells ilha to skip all .onMount() calls when the island is rehydrated from a snapshot. This is useful when your mount logic would duplicate work that was already done on the server:

import 
const ilha: RootBuilder & DirectIslandFactory & {
    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;
    ... 5 more ...;
    onUncaughtError: typeof onUncaughtError;
}
ilha
from "ilha";
const const Island: Island<RootInput, RootState>Island =
const ilha: RootBuilder & DirectIslandFactory & {
    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;
    ... 5 more ...;
    onUncaughtError: typeof onUncaughtError;
}
ilha
.IlhaBuilder<RootInput, RootState, RootDerived, RootActions>.onMount(fn: (ctx: OnMountContext<RootInput, RootState, RootDerived, RootActions>) => (() => void) | void): IlhaBuilder<RootInput, RootState, RootDerived, RootActions>onMount(({ host: Elementhost }) => { var console: Consoleconsole.Console.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
("this is skipped on hydration");
}) .IlhaBuilder<RootInput, RootState, RootDerived, RootActions>.render(fn: (ctx: RenderContext<RootInput, RootState, RootDerived, RootActions>) => string | RawHtml): Island<RootInput, RootState>render(() => <"div": WithRawHtmlAttributeValues<JSX.HTMLAttributes<HTMLDivElement>>div>hello</"div": WithRawHtmlAttributeValues<JSX.HTMLAttributes<HTMLDivElement>>div>); // On the server: await const Island: Island<RootInput, RootState>Island.Island<RootInput, RootState>.hydratable(props: Partial<RootInput>, options: HydratableOptions): Promise<string>hydratable( {}, { HydratableOptions.name: stringname: "my-island",
HydratableOptions.snapshot?: boolean | {
    state?: boolean;
    derived?: boolean;
} | undefined
snapshot
: true,
HydratableOptions.skipOnMount?: boolean | undefinedskipOnMount: true, }, );

.onMount() vs .effect()

.onMount() .effect()
Runs Once after mount After mount, then on every dependency change
Tracks signals No Yes
Receives derived Yes Yes
Receives hydrated Yes No
Cleanup support Yes Yes
Use for One-time setup, third-party libs Reactive sync to external APIs

If you need something to stay in sync with state over time, use .effect() instead.

Notes

  • .onMount() runs client-side only and is never called during SSR.
  • On mount, .onMount() runs after the enter transition (if any) and before .effect() callbacks are registered. See Transition — mount order.
  • Throws from .onMount() (or its returned cleanup) are reported to .onError() / onUncaughtError() with source: "mount".
  • Writing to signals inside .onMount() is safe and will trigger a re-render.
Navigation

Type to search…

↑↓ navigate↵ selectEsc close