Skip to content
Ilha
Esc
↑↓navigate↵open⌘Jpreview
On this page

Installation

Install ilha and start from official templates for Vite SPA and Oxide SPA.

Install ilha with your package manager. For a new project, start from a template so routing and mounting are already wired.

Install

npm install ilha effect
pnpm add ilha effect
yarn add ilha effect
bun add ilha effect
nub add ilha effect
aube add ilha effect

effect is a peer dependency. Ilha atoms and streams sit on Effect.

Templates

Template Command Sandbox
Vite SPA npx giget@latest gh:ilhajs/ilha/templates/vite-spa Open
Oxide SPA npx giget@latest gh:ilhajs/ilha/templates/oxide-spa Open

Vite SPA is a client app with file routes. Oxide SPA adds server pages, frames, and action from oxidejs.

Requirements

  • ESM modules.
  • TypeScript for the best editor support.
  • A browser for mount().
  • JSON-serializable atom snapshots when you hydrate.

Import

import { const atom: AtomFnatom, const mount: (el: Element, fn: Component, opts?: MountOptions) => (() => void)mount, const renderToString: (fn: Component, opts?: RenderToStringOptions) => Promise<string>renderToString } from "ilha";

Named exports you will use most:

import { const atom: AtomFnatom, const when: <A, E = never, R = never>(stream: Stream<A, E, R>, body: (value: A) => Generator<Yielded, View | undefined, View>) => Instruction<undefined, E>when, const mount: (el: Element, fn: Component, opts?: MountOptions) => (() => void)mount, const renderToString: (fn: Component, opts?: RenderToStringOptions) => Promise<string>renderToString, const h: (type: string | Fragment | ComponentFn | JsxComponent, props: PropBag | null | undefined, ...rest: View[]) => VNodeh, 
type Fragment = typeof Fragment
const Fragment: typeof Fragment
Fragment
} from "ilha";

Custom elements come from ilha/define:

import { const define: (name: string, component: Component) => voiddefine } from "ilha/define";

Minimal example

import { const atom: AtomFnatom } from "ilha";

const const Greeting: () => ViewGreeting = () => <JSX.IntrinsicElements.p: HTMLAttributes<HTMLParagraphElement>p>Hello, ilha!</JSX.IntrinsicElements.p: HTMLAttributes<HTMLParagraphElement>p>;

const const Counter: () => ViewCounter = () => {
  const const count: AtomHandle<number>count = atom<number>(init: number | Atom<number> | Effect<number, unknown, AtomRegistry> | Stream<number, unknown, AtomRegistry>, options?: AtomOptions<number> | undefined): AtomHandle<number>atom(0);
  return (
    <JSX.IntrinsicElements.button: ButtonHTMLAttributesbutton type?: string | undefinedtype="button" EventProps<HTMLButtonElement>.onclick?: ((event: Targeted<HTMLButtonElement, MouseEvent>) => void) | undefinedonclick={() => const count: AtomHandle<number>count.AtomHandle<number>.update: (f: (current: number) => number) => voidupdate((n: numbern) => n: numbern + 1)}>
      Count: {const count: AtomHandle<number>count}
    </JSX.IntrinsicElements.button: ButtonHTMLAttributesbutton>
  );
};

Server-side rendering

import { const atom: AtomFnatom, const renderToString: (fn: Component, opts?: RenderToStringOptions) => Promise<string>renderToString } from "ilha";

const const Counter: () => ViewCounter = () => {
  const const count: AtomHandle<number>count = atom<number>(init: number | Atom<number> | Effect<number, unknown, AtomRegistry> | Stream<number, unknown, AtomRegistry>, options?: AtomOptions<number> | undefined): AtomHandle<number>atom(0);
  return (
    <JSX.IntrinsicElements.button: ButtonHTMLAttributesbutton type?: string | undefinedtype="button" EventProps<HTMLButtonElement>.onclick?: ((event: Targeted<HTMLButtonElement, MouseEvent>) => void) | undefinedonclick={() => const count: AtomHandle<number>count.AtomHandle<number>.update: (f: (current: number) => number) => voidupdate((n: numbern) => n: numbern + 1)}>
      Count: {const count: AtomHandle<number>count}
    </JSX.IntrinsicElements.button: ButtonHTMLAttributesbutton>
  );
};

const const html: stringhtml = await function renderToString(fn: Component, opts?: RenderToStringOptions): Promise<string>renderToString(const Counter: () => ViewCounter);

renderToString waits until in-flight work is idle, then serializes. Pass { timeout: ms } to cut off early.

Client-side mounting

import { const mount: (el: Element, fn: Component, opts?: MountOptions) => (() => void)mount } from "ilha";

const const Counter: () => ViewCounter = () => <JSX.IntrinsicElements.p: HTMLAttributes<HTMLParagraphElement>p>Count</JSX.IntrinsicElements.p: HTMLAttributes<HTMLParagraphElement>p>;

const const root: HTMLElement | nullroot = var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("app");
if (const root: HTMLElement | nullroot) { const const unmount: () => voidunmount = function mount(el: Element, fn: Component, opts?: MountOptions): (() => void)mount(const root: HTMLElementroot, const Counter: () => ViewCounter); }

The returned function stops listeners and in-flight work. Call it when you remove the host.

Was this page helpful?