Context and errors
Share atom-backed values with createContext, and catch subtree failures with ErrorBoundary.
Context
Pass values through nested components without threading props. Context values are Effect atoms — reads subscribe, writes update consumers.
import { const atom: AtomFnatom, const context: <A>(ctx: IlhaContext<A>) => AtomHandle<A>Read a context value as an atom handle. Subscribes the active fiber on read.context, const createContext: <A>(defaultValue: A) => IlhaContext<A>createContext } from "ilha";
const const Theme: IlhaContext<string>Theme = createContext<string>(defaultValue: string): IlhaContext<string>createContext("light");
const const Label: () => ViewLabel = () => {
const const theme: AtomHandle<string>theme = context<string>(ctx: IlhaContext<string>): AtomHandle<string>Read a context value as an atom handle. Subscribes the active fiber on read.context(const Theme: IlhaContext<string>Theme);
return <JSX.IntrinsicElements.span: HTMLAttributes<HTMLSpanElement>span>{const theme: AtomHandle<string>theme}</JSX.IntrinsicElements.span: HTMLAttributes<HTMLSpanElement>span>;
};
const const App: () => ViewApp = () => {
const const mode: AtomHandle<string>mode = atom<string>(init: string | Atom<string> | Effect<string, unknown, AtomRegistry> | Stream<string, unknown, AtomRegistry>): AtomHandle<string>atom("dark");
return (
<const Theme: IlhaContext<string>Theme.IlhaContext<string>.Provider: (props: ContextProviderProps<string>) => ViewProvider ContextProviderProps<string>.value: stringvalue={const mode: AtomHandle
() => string
mode()}>
<JSX.IntrinsicElements.button: ButtonHTMLAttributesbutton type?: string | undefinedtype="button" EventProps<HTMLButtonElement>.onclick?: ((event: Targeted<HTMLButtonElement, MouseEvent>) => void) | undefinedonclick={() => const mode: AtomHandle<string>mode.AtomHandle<string>.set: (next: string) => voidset("light")}>
Light
</JSX.IntrinsicElements.button: ButtonHTMLAttributesbutton>
<const Label: () => ViewLabel />
</const Theme: IlhaContext<string>Theme.IlhaContext<string>.Provider: (props: ContextProviderProps<string>) => ViewProvider>
);
};
createContext(defaultValue)returns a context object with aProvider.- Wrap a subtree in
<Theme.Provider value={…}>. - Call
context(Theme)in a descendant to get anAtomHandle.
Without a provider, context() returns a handle over the default value. Nested providers override outer ones.
Call context() during render under a fiber — same rule as reading an atom.
Error boundaries
Wrap a subtree in ErrorBoundary to paint a fallback when a child fails. Return a reset callback so the user can retry.
import { const ErrorBoundary: (props: ErrorBoundaryProps) => ViewCatch subtree failures and paint a fallback. Supports reset().ErrorBoundary } from "ilha";
const const Boom: () => neverBoom = () => {
throw new var Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+2 overloads)
Error("boom");
};
const const App: () => ViewApp = () => (
<const ErrorBoundary: (props: ErrorBoundaryProps) => ViewCatch subtree failures and paint a fallback. Supports reset().ErrorBoundary
ErrorBoundaryProps.fallback?: ErrorFallback | undefinedfallback={({ error: Errorerror, reset: () => voidreset }) => (
<JSX.IntrinsicElements.div: HTMLAttributes<HTMLDivElement>div>
<JSX.IntrinsicElements.p: HTMLAttributes<HTMLParagraphElement>p>{error: Errorerror.Error.message: stringmessage}</JSX.IntrinsicElements.p: HTMLAttributes<HTMLParagraphElement>p>
<JSX.IntrinsicElements.button: ButtonHTMLAttributesbutton type?: string | undefinedtype="button" EventProps<HTMLButtonElement>.onclick?: ((event: Targeted<HTMLButtonElement, MouseEvent>) => void) | undefinedonclick={reset: () => voidreset}>
Retry
</JSX.IntrinsicElements.button: ButtonHTMLAttributesbutton>
</JSX.IntrinsicElements.div: HTMLAttributes<HTMLDivElement>div>
)}
ErrorBoundaryProps.onError?: ((error: Error) => void) | undefinedonError={(error: Errorerror) => var console: ConsoleThe `console` module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
* A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream.
* A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v24.x/api/process.html#processstdout) and
[`process.stderr`](https://nodejs.org/docs/latest-v24.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module.
_**Warning**_: The global console object's methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v24.x/api/process.html#a-note-on-process-io) for
more information.
Example using the global `console`:
```js
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
```
Example using the `Console` class:
```js
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
```console.Console.error(message?: any, ...optionalParams: any[]): void (+2 overloads)Prints to `stderr` with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html)
(the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v24.x/api/util.html#utilformatformat-args)).
```js
const code = 5;
console.error('error #%d', code);
// Prints: error #5, to stderr
console.error('error', code);
// Prints: error 5, to stderr
```
If formatting elements (e.g. `%d`) are not found in the first string then
[`util.inspect()`](https://nodejs.org/docs/latest-v24.x/api/util.html#utilinspectobject-options) is called on each argument and the
resulting string values are concatenated. See [`util.format()`](https://nodejs.org/docs/latest-v24.x/api/util.html#utilformatformat-args)
for more information.error(error: Errorerror)}
>
<const Boom: () => neverBoom />
</const ErrorBoundary: (props: ErrorBoundaryProps) => ViewCatch subtree failures and paint a fallback. Supports reset().ErrorBoundary>
);
| Prop | Role |
|---|---|
fallback({ error, reset }) |
View to paint after a failure |
onError(error) |
Optional side channel (logging) |
children |
Protected subtree |
Without a boundary, a failed child hole paints the default [data-ilha-error] view and the parent stays up. Route-level failures still use @ilha/router +error — see Error boundaries.