Error Boundary
Catches errors thrown inside reactive child expressions and renders a fallback element instead of crashing the whole tree. Apply to any container element.
Only errors in reactive children (functions returning element arrays) are caught. Errors during static construction propagate normally — those are programming errors, not runtime data errors.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
fallback | DomphyElement | ((error, reset) => DomphyElement) | { div: "An error occurred." } | Fallback element shown when a child throws. Pass a factory to receive the error and a reset callback. |
onError | (error: unknown) => void | — | Optional callback invoked on every caught error, useful for logging and telemetry. |
Basic fallback
Provide a static element as fallback for a simple message when you do not need to display the error or offer a retry:
{
div: (l) => renderUserContent(l),
$: [errorBoundary({ fallback: { p: "Something went wrong." } })],
}
Factory fallback with reset
Pass a function to receive the thrown error and a reset callback. Calling reset() clears the boundary so the next reactive evaluation runs again:
{
div: (l) => dataState.get(l).map(renderItem),
$: [
errorBoundary({
fallback: (error, reset) => ({
div: [
{ p: `Error: ${String(error)}` },
{ button: "Try again", onClick: reset },
],
}),
}),
],
}
With error logging
Use onError to forward errors to your monitoring stack while still showing a friendly fallback:
{
section: (l) => renderDashboard(l),
$: [
errorBoundary({
fallback: { div: "Dashboard failed to load." },
onError: (error) => reportToSentry(error),
}),
],
}
Customization
Must see the source of patch at the bottom of each patch page to understand the structure then code it still code as html native element.
There are four levels of customization, in increasing order of effort:
- Patch props. Each patch exposes a small, stable set of props—typically fewer than five. Lowest friction.
- Context attributes. Use
dataTone,dataSize, anddataDensityon a container to shift tone, size, or density for an entire subtree without touching individual elements. - Inline override. Native-wins merge strategy: any property set directly on the element overrides the patch value.
- Create a variant. Clone a similar patch and edit it. Use this only when you need a reusable custom version.
Formulas
Unit - U = fontSize / 4 - convert final values with themeSpacing(n).
Size - n = intrinsic text lines, w = wrapping level, d = density factor:
height = (n * 6 + 2 * d * w) * U
paddingBlock = d * w * U
paddingInline = ceil(3 / w) * d * w * U
radius = d * w * U
Base density d = 1.5:
| U | w=0 | w=1 | w=2 | w=3 |
|---|---|---|---|---|
height (n = 1) | 6 | 9 | 12 | 15 |
| paddingBlock | 0 | 1.5 | 3 | 4.5 |
| paddingInline | 3 | 4.5 | 6 | 4.5 |
| radius | 0 | 1.5 | 3 | 4.5 |
Tone - K = N / 2 where N is the palette length. For N = 18, K = 9.
| Role | Shift | n=0 |
|---|---|---|
| Background | parent +/- n | 0 |
| Text | bg + K | 6 |
| Border | bg + K/2 | 3 |
| Hover | bg + 2K/3 | 4 |
| Selected / Focus | above +/- K/3 | 2-4 |
State shift range: K/3 <= delta <= 2K/3.
import type { DomphyElement, PartialElement } from "@domphy/core";
/**
* Catches errors thrown inside reactive child expressions and renders a
* fallback element instead of crashing the whole tree. Apply to any container.
*
* Only errors in *reactive* children (functions returning element arrays) are
* caught. Errors during static construction propagate normally — those are
* programming errors, not runtime data errors.
*
* @hostTag any
* @param props.fallback - Fallback element or factory `(error, reset) => element`. Defaults to a plain error message div.
* @param props.onError - Optional callback for logging/telemetry.
* @example { div: (l) => renderUserContent(l), $: [errorBoundary({ fallback: { p: "Something went wrong." } })] }
*/
function errorBoundary(
props: {
fallback?:
| DomphyElement
| ((error: unknown, reset: () => void) => DomphyElement);
onError?: (error: unknown) => void;
} = {},
): PartialElement {
return {
_onError: (node, error, reset) => {
props.onError?.(error);
const fallbackEl =
typeof props.fallback === "function"
? props.fallback(error, reset)
: (props.fallback ??
({ div: "An error occurred." } as DomphyElement));
node.children.update([fallbackEl]);
},
};
}
export { errorBoundary };