Skip to content

default

default: (…args) => Element & object

Defined in: aberdeen.ts:3729

The main Aberdeen API. A is itself a callable function for building reactive DOM trees (creating elements, setting attributes, adding content). All other Aberdeen functions and values are available as properties on A.

clean: (cleaner) => void

Registers a cleanup function to be executed just before the current reactive scope is destroyed or redraws.

This is useful for releasing resources, removing manual event listeners, or cleaning up side effects associated with the scope. Cleaners are run in reverse order of registration.

Scopes are created by functions like derive, mount, A (when given a render function), and internally by constructs like onEach.

Registers a cleanup function to be executed just before the current reactive scope is destroyed or redraws.

This is useful for releasing resources, removing manual event listeners, or cleaning up side effects associated with the scope. Cleaners are run in reverse order of registration.

Scopes are created by functions like derive, mount, A (when given a render function), and internally by constructs like onEach.

() => void

The function to execute during cleanup.

void

Maintaing a sum for a changing array

const $numbers = A.proxy([3, 5, 10]);
let $sum = A.proxy(0);
// Show the array items and maintain the sum
A.onEach($numbers, (item, index) => {
A(`code#${index}${item}`);
// We'll update $sum.value using peek, as += first does a read, but
// we don't want to subscribe.
A.peek(() => $sum.value += item);
// Clean gets called before each rerun for a certain item index
// No need for peek here, as the clean code doesn't run in an
// observer scope.
A.clean(() => $sum.value -= item);
})
// Show the sum
A('h1 text=', $sum);
// Make random changes to the array
const rnd = () => 0|(Math.random()*20);
setInterval(() => $numbers[rnd()] = rnd(), 1000);

clone: <T>(src) => T

Clone an (optionally proxied) object or array.

Clone an (optionally proxied) object or array.

T extends object

The type of the objects being copied.

T

The object or array to clone. If it is proxied, clone will subscribe to any changes to the (nested) data structure.

T

A new unproxied array or object (of the same type as src), containing a deep copy of src.

A new unproxied array or object (of the same type as src), containing a deep copy of src.

copy: {<T>(dst, src): boolean; <T>(dst, dstKey, src): boolean; }

Recursively copies properties or array items from src to dst. It’s designed to work efficiently with reactive proxies created by proxy.

  • Minimizes Updates: When copying between objects/arrays (proxied or not), if a nested object exists in dst with the same constructor as the corresponding object in src, copy will recursively copy properties into the existing dst object instead of replacing it. This minimizes change notifications for reactive (proxied) destinations.
  • Fast with Proxies: When copying to/from proxied objects, copy uses Aberdeen internals to speed things up (compared to a non-Aberdeen-aware deep copy).

<T>(dst, src): boolean

Recursively copies properties or array items from src to dst. It’s designed to work efficiently with reactive proxies created by proxy.

  • Minimizes Updates: When copying between objects/arrays (proxied or not), if a nested object exists in dst with the same constructor as the corresponding object in src, copy will recursively copy properties into the existing dst object instead of replacing it. This minimizes change notifications for reactive (proxied) destinations.
  • Fast with Proxies: When copying to/from proxied objects, copy uses Aberdeen internals to speed things up (compared to a non-Aberdeen-aware deep copy).

T extends object

The type of the objects being copied.

T

The destination object/array/Map (proxied or unproxied).

T

The source object/array/Map (proxied or unproxied). It won’t be modified.

boolean

true if any changes were made to dst, or false if not.

Error if attempting to copy an array into a non-array or vice versa.

Basic Copy

const $source = A.proxy({ a: 1, b: { c: 2 } });
const $dest = A.proxy({ b: { d: 3 } });
A.copy($dest, $source);
console.log($dest); // proxy({ a: 1, b: { c: 2 } })
A.copy($dest, 'b', { e: 4 });
console.log($dest); // proxy({ a: 1, b: { e: 4 } })

<T>(dst, dstKey, src): boolean

Like above, but copies src into dst[dstKey]. This is useful if you’re unsure if dst[dstKey] already exists (as the right type of object) or if you don’t want to subscribe to dst[dstKey].

T extends object

T

keyof T

Optional key in dst to copy into.

T[keyof T]

boolean

true if any changes were made to dst, or false if not.

count: (proxied) => ValueRef<number>

Reactively counts the number of properties in an object.

Reactively counts the number of properties in an object.

TargetType

The observable object to count. In case an array, Map, or Set is passed in, a ref to its .length or .size will be returned.

ValueRef<number>

an observable object for which the value property reflects the number of properties in proxied with a value other than undefined, or the collection size for arrays, Maps, and Sets.

const $items = A.proxy({x: 3, y: 7} as any);
const $count = A.count($items);
// Create a DOM text node for the count:
A('div text=', $count);
// <div>2</div>
// Or we can use it in an {@link derive} function:
A(() => console.log("The count is now", $count.value));
// The count is now 2
// Adding/removing items will update the count
$items.z = 12;
// Asynchronously, after 0ms:
// <div>3</div>
// The count is now 3

an observable object for which the value property reflects the number of properties in proxied with a value other than undefined, or the collection size for arrays, Maps, and Sets.

cssVars: Record<string, string>

A reactive object containing CSS variable definitions.

Any property you assign to cssVars becomes available as a CSS custom property throughout your application.

Use setSpacingCssVars to optionally initialize cssVars[1] through cssVars[12] with an exponential spacing scale.

When you reference a CSS variable in Aberdeen using the $ prefix (e.g., $primary), it automatically resolves to var(--primary). For numeric keys (which can’t be used directly as CSS custom property names), Aberdeen prefixes them with m (e.g., $3 becomes var(--m3)).

When you add the first property to cssVars, Aberdeen automatically creates a reactive <style> tag in <head> containing the :root CSS custom property declarations. The style tag is automatically removed if cssVars becomes empty.

CUSTOM_DUMP: symbol

When set on an object or its prototype chain, dump calls this as a render function (with the object as this) instead of its default recursive rendering. If the value is not a function, it’s treated as a string to display.

darkMode: () => boolean

Returns whether the user’s browser prefers a dark color scheme.

This function is reactive - scopes that call it will re-execute when the browser’s color scheme preference changes (via the prefers-color-scheme media query).

Use this in combination with A and cssVars to implement theme switching:

Returns whether the user’s browser prefers a dark color scheme.

This function is reactive - scopes that call it will re-execute when the browser’s color scheme preference changes (via the prefers-color-scheme media query).

Use this in combination with A and cssVars to implement theme switching:

boolean

true if the browser prefers dark mode, false if it prefers light mode.

import A from 'aberdeen';
// Reactively set colors based on browser preference
A(() => {
A.cssVars.bg = A.darkMode() ? '#1a1a1a' : '#ffffff';
A.cssVars.fg = A.darkMode() ? '#e5e5e5' : '#000000';
});
A('div bg:$bg fg:$fg p:1rem #Colors change based on system dark mode preference');

true if the browser prefers dark mode, false if it prefers light mode.

derive: <T>(func) => ValueRef<T>

Creates a reactive scope that automatically re-executes the provided function whenever any proxied data (created by proxy) read during its last execution changes, storing its return value in an observable.

Updates are batched and run asynchronously shortly after the changes occur. Use clean to register cleanup logic for the scope. Use peek or unproxy within the function to read proxied data without subscribing to it.

Creates a reactive scope that automatically re-executes the provided function whenever any proxied data (created by proxy) read during its last execution changes, storing its return value in an observable.

Updates are batched and run asynchronously shortly after the changes occur. Use clean to register cleanup logic for the scope. Use peek or unproxy within the function to read proxied data without subscribing to it.

T

() => T

The function to execute reactively. Any DOM manipulations should typically be done using A within this function. Its return value will be made available as an observable returned by the derive() function.

ValueRef<T>

An observable object, with its value property containing whatever the last run of func returned.

Observation creating UI components

const $data = A.proxy({ user: 'Frank', notifications: 42 });
A('main', () => {
console.log('Welcome');
A('h3#Welcome, ' + $data.user); // Reactive text
A.derive(() => {
// When $data.notifications changes, only this inner scope reruns,
// leaving the `<p>Welcome, ..</p>` untouched.
console.log('Notifications');
A('code.notification-badge text=', $data.notifications);
A('a text=Notify! click=', () => $data.notifications++);
});
});

Note that the above could just as easily be done using A(func) instead of derive(func).

Observation with return value

const $counter = A.proxy(0);
setInterval(() => $counter.value++, 1000);
const $double = A.derive(() => $counter.value * 2);
A('h3', () => {
A(`#counter=${$counter.value} double=${$double.value}`);
})

An observable object, with its value property containing whatever the last run of func returned.

disableCreateDestroy: () => void

Make the create and destroy special properties no-ops.

This is useful from within automated testing environments, where the transitioning new and lingering old elements may make writing reliable selectors difficult.

As this is only intended for testing, there’s no way to re-enable the special properties once disabled.

Make the create and destroy special properties no-ops.

This is useful from within automated testing environments, where the transitioning new and lingering old elements may make writing reliable selectors difficult.

As this is only intended for testing, there’s no way to re-enable the special properties once disabled.

void

dump: <T>(data) => T

Renders a live, recursive dump of a proxied data structure (or any value) into the DOM at the current A insertion point.

Uses <ul> and <li> elements to display object properties and array items. Updates reactively if the dumped data changes. Primarily intended for debugging purposes.

Renders a live, recursive dump of a proxied data structure (or any value) into the DOM at the current A insertion point.

Uses <ul> and <li> elements to display object properties and array items. Updates reactively if the dumped data changes. Primarily intended for debugging purposes.

T

The type of the data being dumped.

T

The proxied data structure (or any value) to display.

T

The original data argument, allowing for chaining.

Dumping reactive state

import A from 'aberdeen';
const $state = A.proxy({
user: { name: 'Frank', kids: 1 },
items: ['a', 'b']
});
A('h2#Live State Dump');
A.dump($state);
// Change state later, the dump in the DOM will update
setTimeout(() => { $state.user.kids++; $state.items.push('c'); }, 2000);

The original data argument, allowing for chaining.

freeze: () => () => void

Pause processing of reactive updates until the returned thaw function is called.

While frozen, changes to observed data still accumulate, but no re-renders run. Freezes stack: if there are multiple outstanding freezes, redraws resume only once the last one is thawed. This is useful to batch an async burst of changes into a single update pass, or to hold the UI steady (e.g. the dev tools use it for “freeze redraws”).

Pause processing of reactive updates until the returned thaw function is called.

While frozen, changes to observed data still accumulate, but no re-renders run. Freezes stack: if there are multiple outstanding freezes, redraws resume only once the last one is thawed. This is useful to batch an async burst of changes into a single update pass, or to hold the UI steady (e.g. the dev tools use it for “freeze redraws”).

A function that releases this freeze. Calling it more than once has no effect.

() => void

const thaw = A.freeze();
// ...make many changes without intermediate redraws...
thaw(); // redraws run now (if no other freezes remain)

A function that releases this freeze. Calling it more than once has no effect.

insertCss: (style) => string

Inserts CSS rules into the document, scoping them with a unique class name.

The style parameter can be either:

  • A concise style string (for rules applying to the root class).
  • An object where keys are selectors (with & representing the root class) and values are concise style strings or nested objects. When the key does not contain &, it is treated as a descendant selector. So {p: "color:red"} becomes ".AbdStlX p { color: red; }" with AbdStlX being the generated class name.

Concise style strings use two syntaxes (same as inline CSS in A):

  • Short form key:value (no space after colon): The value ends at the next whitespace. Example: 'm:$3 bg:red r:8px'
  • Long form key: value; (space after colon): The value continues until a semicolon. Example: 'box-shadow: 2px 0 6px black; transition: all 0.3s ease;'

Both forms can be mixed: 'm:$3 box-shadow: 0 2px 4px rgba(0,0,0,0.2); bg:$cardBg'

Supports the same CSS shortcuts as A and CSS variable references with $ (e.g., $primary, $3).

CSS is inserted into the in an order relative to other insert(Global)Css items that is consistent based on when the containing Aberdeen scope was first defined. This allows changing styles without changing order-based precedence.

Inserts CSS rules into the document, scoping them with a unique class name.

The style parameter can be either:

  • A concise style string (for rules applying to the root class).
  • An object where keys are selectors (with & representing the root class) and values are concise style strings or nested objects. When the key does not contain &, it is treated as a descendant selector. So {p: "color:red"} becomes ".AbdStlX p { color: red; }" with AbdStlX being the generated class name.

Concise style strings use two syntaxes (same as inline CSS in A):

  • Short form key:value (no space after colon): The value ends at the next whitespace. Example: 'm:$3 bg:red r:8px'
  • Long form key: value; (space after colon): The value continues until a semicolon. Example: 'box-shadow: 2px 0 6px black; transition: all 0.3s ease;'

Both forms can be mixed: 'm:$3 box-shadow: 0 2px 4px rgba(0,0,0,0.2); bg:$cardBg'

Supports the same CSS shortcuts as A and CSS variable references with $ (e.g., $primary, $3).

CSS is inserted into the in an order relative to other insert(Global)Css items that is consistent based on when the containing Aberdeen scope was first defined. This allows changing styles without changing order-based precedence.

string | object

A concise style string or a style object.

string

The unique class name prefix used for scoping (e.g., .AbdStl1). Use this prefix with A to apply the styles.

Basic Usage with Shortcuts and CSS Variables

const cardClass = A.insertCss({
'&': 'bg:white p:$4 r:8px transition: background-color 0.3s;',
'&:hover': 'bg:#f5f5f5',
});
A('section', cardClass, () => {
A('p#Card content');
});

Nested Selectors and Media Queries

const formClass = A.insertCss({
'&': 'bg:#0004 p:$3 r:$2',
button: {
'&': 'bg:$primary fg:white p:$2 r:4px cursor:pointer',
'&:hover': 'bg:$primaryHover',
'&:disabled': 'bg:#ccc cursor:not-allowed',
'.icon': 'display:inline-block mr:$1',
'@media (max-width: 600px)': 'p:$1 font-size:14px'
}
});
A('form', formClass, () => {
A('button', () => {
A('span.icon text=🔥');
A('#Click Me');
});
});

Complex CSS Values

const badge = A.insertCss({
'&::before': 'content: "★"; color:gold mr:$1',
'&': 'position:relative box-shadow: 0 2px 8px rgba(0,0,0,0.15);'
});
A(badge + ' span#Product Name');

The unique class name prefix used for scoping (e.g., .AbdStl1). Use this prefix with A to apply the styles.

insertGlobalCss: (style) => void

Inserts CSS rules globally (unscoped).

Works exactly like insertCss, but without prefixing selectors with a unique class name. This is useful for global resets, base styles, or styles that need to apply to the entire document.

Accepts the same concise style string syntax and CSS shortcuts as insertCss. See insertCss for detailed documentation on syntax and shortcuts.

Inserts CSS rules globally (unscoped).

Works exactly like insertCss, but without prefixing selectors with a unique class name. This is useful for global resets, base styles, or styles that need to apply to the entire document.

Accepts the same concise style string syntax and CSS shortcuts as insertCss. See insertCss for detailed documentation on syntax and shortcuts.

object

Object with selectors as keys and concise CSS strings as values.

CSS is inserted into the in an order relative to other insert(Global)Css items that is consistent based on when the containing Aberdeen scope was first defined. This allows changing styles without changing order-based precedence.

void

Global Reset and Base Styles

// Set up global styles using CSS shortcuts
A.insertGlobalCss({
"*": "m:0 p:0 box-sizing:border-box",
"body": "font-family: system-ui, sans-serif; m:0 p:$3 bg:#434 fg:#d0dafa",
"a": "text-decoration:none fg:#57f",
"a:hover": "text-decoration:underline",
"code": "font-family:monospace bg:#222 fg:#afc p:4px r:3px"
});
A('h2#Title without margins');
A('a#This is a link');
A('code#const x = 42;');

Responsive Global Styles

A.insertGlobalCss({
"html": "font-size:16px",
"body": "line-height:1.6",
"h1, h2, h3": "font-weight:600 mt:$4 mb:$2",
"@media (max-width: 768px)": {
"html": "font-size:14px",
"body": "p:$2"
},
"@media (prefers-color-scheme: dark)": {
"body": "bg:#1a1a1a fg:#e5e5e5",
"code": "bg:#2a2a2a"
}
});

At-rules such as @media and @keyframes should use nested objects. For keyframes, the step selectors (0%, 50%, 100%, etc.) become the nested keys and each value should be a concise CSS declaration string.

Animation Keyframes

A.insertGlobalCss({
"@keyframes connection-pulse": {
"0%": "box-shadow: inset 0 0 0 0 rgba(255, 70, 70, 0.4);",
"50%": "box-shadow: inset 0 0 0 6px rgba(255, 70, 70, 0.08);",
"100%": "box-shadow: inset 0 0 0 0 rgba(255, 70, 70, 0.4);"
}
});

invertString: (input) => string

Creates a new string that has the opposite sort order compared to the input string.

This is achieved by flipping the bits of each character code in the input string. The resulting string is intended for use as a sort key, particularly with the makeKey function in onEach, to achieve a descending sort order.

Warning: The output string will likely contain non-printable characters or appear as gibberish and should not be displayed to the user.

Creates a new string that has the opposite sort order compared to the input string.

This is achieved by flipping the bits of each character code in the input string. The resulting string is intended for use as a sort key, particularly with the makeKey function in onEach, to achieve a descending sort order.

Warning: The output string will likely contain non-printable characters or appear as gibberish and should not be displayed to the user.

string

The string whose sort order needs to be inverted.

string

A new string that will sort in the reverse order of the input string.

const $users = A.proxy([
{ id: 1, name: 'Charlie', score: 95 },
{ id: 2, name: 'Alice', score: 100 },
{ id: 3, name: 'Bob', score: 90 },
]);
A.onEach($users, ($user) => {
A(`p#${$user.name}: ${$user.score}`);
}, ($user) => A.invertString($user.name)); // Reverse alphabetic order

onEach for usage with sorting.

A new string that will sort in the reverse order of the input string.

isEmpty: (proxied) => boolean

Reactively checks if an observable array, object, Map, or Set is empty.

This function not only returns the current emptiness state but also establishes a reactive dependency. If the emptiness state of the proxied object or array changes later (e.g., an item is added to an empty array, or the last property is deleted from an object), the scope that called isEmpty will be automatically scheduled for re-evaluation.

Reactively checks if an observable array, object, Map, or Set is empty.

This function not only returns the current emptiness state but also establishes a reactive dependency. If the emptiness state of the proxied object or array changes later (e.g., an item is added to an empty array, or the last property is deleted from an object), the scope that called isEmpty will be automatically scheduled for re-evaluation.

TargetType

The observable array, object, Map, or Set to check.

boolean

true if the array has length 0, the Map/Set has size 0, or the object has no own enumerable properties, false otherwise.

const $items = A.proxy([]);
// Reactively display a message if the items array is empty
A('div', () => {
if (A.isEmpty($items)) {
A('p i#No items yet!');
} else {
A.onEach($items, item => A('p#'+item));
}
});
// Adding an item will automatically remove the "No items yet!" message
setInterval(() => {
if (!$items.length || Math.random()>0.5) $items.push('Item');
else $items.length = 0;
}, 1000)

true if the array has length 0, the Map/Set has size 0, or the object has no own enumerable properties, false otherwise.

map: {<K, IN, OUT>(source, func): Map<K, OUT>; <IN, OUT>(source, func): OUT[]; <IN, IN_KEY, OUT>(source, func): Record<string | symbol, OUT>; }

Reactively maps/filters items from a proxied source array or object to a new proxied array or object.

It iterates over the target proxy. For each item, it calls func.

  • If func returns a value, it’s added to the result proxy under the same key/index.
  • If func returns undefined, the item is skipped (filtered out).

The returned proxy automatically updates when:

  • Items are added/removed/updated in the target proxy.
  • Any proxied data read within the func call changes (for a specific item).

<K, IN, OUT>(source, func): Map<K, OUT>

When using a Map as source.

K

IN

OUT

Map<K, IN>

(value, key) => OUT

Map<K, OUT>

<IN, OUT>(source, func): OUT[]

When using an array as source.

IN

OUT

IN[]

(value, index) => OUT

OUT[]

<IN, IN_KEY, OUT>(source, func): Record<string | symbol, OUT>

When using an object as source.

IN

IN_KEY extends string | number | symbol

OUT

Record<IN_KEY, IN>

(value, index) => OUT

Record<string | symbol, OUT>

A new proxied array or object containing the mapped values.

merge: {<T>(dst, value): boolean; <T>(dst, dstKey, value): boolean; }

Like copy, but uses merge semantics. Properties in dst not present in src are kept. null/undefined in src delete properties in dst.

<T>(dst, value): boolean

Like copy, but uses merge semantics. Properties in dst not present in src are kept. null/undefined in src delete properties in dst.

T extends object

T

Partial<T>

boolean

Basic merge

const source = { b: { c: 99 }, d: undefined }; // d: undefined will delete
const $dest = A.proxy({ a: 1, b: { x: 5 }, d: 4 });
A.merge($dest, source);
A.merge($dest, 'b', { y: 6 }); // merge into $dest.b
A.merge($dest, 'c', { z: 7 }); // $dest.c doesn't exist yet, so it will just be assigned
console.log($dest); // proxy({ a: 1, b: { c: 99, x: 5, y: 6 }, c: { z: 7 } })

<T>(dst, dstKey, value): boolean

Like copy, but uses merge semantics. Properties in dst not present in src are kept. null/undefined in src delete properties in dst.

T extends object

T

keyof T

Partial<T[typeof dstKey]>

boolean

Basic merge

const source = { b: { c: 99 }, d: undefined }; // d: undefined will delete
const $dest = A.proxy({ a: 1, b: { x: 5 }, d: 4 });
A.merge($dest, source);
A.merge($dest, 'b', { y: 6 }); // merge into $dest.b
A.merge($dest, 'c', { z: 7 }); // $dest.c doesn't exist yet, so it will just be assigned
console.log($dest); // proxy({ a: 1, b: { c: 99, x: 5, y: 6 }, c: { z: 7 } })

mount: (parentElement, func) => void

Attaches a reactive Aberdeen UI fragment to an existing DOM element. Without the use of this function, A will assume document.body as its root.

It creates a top-level reactive scope associated with the parentElement. The provided function func is executed immediately within this scope. Any proxied data read by func will cause it to re-execute when the data changes, updating the DOM elements created within it.

Calls to A inside func will append nodes to parentElement. You can nest derive or other A scopes within func. Use unmountAll to clean up all mounted scopes and their DOM nodes.

Mounting scopes happens reactively, meaning that if this function is called from within another (derive or A or mount) scope that gets cleaned up, so will the mount.

Attaches a reactive Aberdeen UI fragment to an existing DOM element. Without the use of this function, A will assume document.body as its root.

It creates a top-level reactive scope associated with the parentElement. The provided function func is executed immediately within this scope. Any proxied data read by func will cause it to re-execute when the data changes, updating the DOM elements created within it.

Calls to A inside func will append nodes to parentElement. You can nest derive or other A scopes within func. Use unmountAll to clean up all mounted scopes and their DOM nodes.

Mounting scopes happens reactively, meaning that if this function is called from within another (derive or A or mount) scope that gets cleaned up, so will the mount.

Element

The native DOM Element to which the UI fragment will be appended.

() => void

The function that defines the UI fragment, typically containing calls to A.

void

Basic Mount

// Create a pre-existing DOM structure (without Aberdeen)
document.body.innerHTML = `<h3>Static content <span id="title-extra"></span></h3><div class="box" id="app-root"></div>`;
import A from 'aberdeen';
const $runTime = A.proxy(0);
setInterval(() => $runTime.value++, 1000);
A.mount(document.getElementById('app-root'), () => {
A('h4#Aberdeen App');
A(`p#Run time: ${$runTime.value}s`);
// Conditionally render some content somewhere else in the static page
if ($runTime.value&1) {
A.mount(document.getElementById('title-extra'), () =>
A(`i#(${$runTime.value}s)`)
);
}
});

Note how the inner mount behaves reactively as well, automatically unmounting when it’s parent observer scope re-runs.

multiMap: {<IN, OUT>(source, func): OUT; <K, IN, OUT>(source, func): OUT; <K, IN, OUT>(source, func): OUT; }

Reactively maps items from a source proxy (array or object) to a target proxied object, where each source item can contribute multiple key-value pairs to the target.

It iterates over the target proxy. For each item, it calls func.

  • If func returns an object, all key-value pairs from that object are added to the result proxy.
  • If func returns undefined, the item contributes nothing.

The returned proxy automatically updates when:

  • Items are added/removed/updated in the target proxy.
  • Any proxied data read within the func call changes (for a specific item).
  • If multiple input items produce the same output key, the last one processed usually “wins”, but the exact behavior on collision depends on update timing.

This is useful for “flattening” or “indexing” data, or converting an observable array to an observable object.

<IN, OUT>(source, func): OUT

When using an array as source.

IN

OUT extends object

IN[]

(value, index) => OUT

OUT

<K, IN, OUT>(source, func): OUT

When using an object as source.

K extends string | number | symbol

IN

OUT extends object

Record<K, IN>

(value, index) => OUT

OUT

<K, IN, OUT>(source, func): OUT

When using a Map as source.

K

IN

OUT extends object

Map<K, IN>

(value, key) => OUT

OUT

A new proxied object containing the aggregated key-value pairs.

OPAQUE: symbol

A symbol that controls how Aberdeen handles an object in copy operations and proxy wrapping.

The presence of this symbol (regardless of its value) prevents deep-copying: the object is stored and passed by reference in clone and copy.

The value of the symbol controls proxy wrapping when the object is read from reactive state:

  • Truthy (e.g. true): the object is fully opaque — it is not wrapped in a proxy, so its properties are not observable. Use this for objects that break when proxied (e.g. class instances with internal slots, Promises) or that must be invisible to Aberdeen’s reactive system.
  • Falsy (e.g. false): the object is still wrapped in a proxy, so reads on its properties create reactive dependencies as normal — only deep-copying is suppressed.

NO_COPY: symbol

Use OPAQUE instead. This is an alias kept for backward compatibility.

onEach: {<K, T>(target, render, makeKey?): void; <T>(target, render, makeKey?): void; <T>(target, render, makeKey?): void; <K, T>(target, render, makeKey?): void; }

Reactively iterates over the items of an observable array, object, Map, or Set, optionally rendering content for each item.

Automatically updates when items are added, removed, or modified.

<K, T>(target, render, makeKey?): void

K

T

Map<K, T>

(value, key) => void

(value, key) => SortKeyType

void

<T>(target, render, makeKey?): void

T

Set<T>

(value) => void

(value) => SortKeyType

void

<T>(target, render, makeKey?): void

T

readonly T[]

(value, index) => void

(value, index) => SortKeyType

void

<K, T>(target, render, makeKey?): void

K extends string | number | symbol

T

Record<K, undefined | T>

(value, index) => void

(value, index) => SortKeyType

void

partition: {<OUT_K, IN_V>(source, func): Record<OUT_K, Record<number, IN_V>>; <IN_K, OUT_K, IN_V>(source, func): Record<OUT_K, Record<IN_K, IN_V>>; <IN_K, OUT_K, IN_V>(source, func): Record<OUT_K, Record<IN_K, IN_V>>; }

Reactively partitions items from a source proxy (array or object) into multiple “bucket” proxies based on keys determined by a classifier function.

This function iterates through the source proxy using onEach. For each item, it calls the classifier func, which should return:

  • A single key (OUT_K): The item belongs to the bucket with this key.
  • An array of keys (OUT_K[]): The item belongs to all buckets specified in the array.
  • undefined: The item is not placed in any bucket.

The function returns a main proxied object. The keys of this object are the bucket keys (OUT_K) returned by func. Each value associated with a bucket key is another proxied object (the “bucket”). This inner bucket object maps the original keys/indices from the source to the items themselves that were classified into that bucket.

The entire structure is reactive. Changes in the source proxy (adding/removing/updating items) or changes in dependencies read by the func will cause the output partitioning to update automatically. Buckets are created dynamically as needed and removed when they become empty.

<OUT_K, IN_V>(source, func): Record<OUT_K, Record<number, IN_V>>

When using an object as array.

OUT_K extends string | number | symbol

IN_V

IN_V[]

(value, key) => OUT_K | OUT_K[]

Record<OUT_K, Record<number, IN_V>>

<IN_K, OUT_K, IN_V>(source, func): Record<OUT_K, Record<IN_K, IN_V>>

When using an object as source.

IN_K extends string | number | symbol

OUT_K extends string | number | symbol

IN_V

Record<IN_K, IN_V>

(value, key) => OUT_K | OUT_K[]

Record<OUT_K, Record<IN_K, IN_V>>

<IN_K, OUT_K, IN_V>(source, func): Record<OUT_K, Record<IN_K, IN_V>>

When using a Map as source.

IN_K extends string | number | symbol

OUT_K extends string | number | symbol

IN_V

Map<IN_K, IN_V>

(value, key) => OUT_K | OUT_K[]

Record<OUT_K, Record<IN_K, IN_V>>

A proxied object where keys are the bucket identifiers (OUT_K) and values are proxied Records (Record<IN_K | number, IN_V>) representing the buckets. Each bucket maps original source keys/indices to the items belonging to that bucket.

peek: {<T, K>(target, key): T[K]; <K, V>(target, key): V; <T>(target, key): T; <T>(target): T; }

Executes a function or retrieves a value without creating subscriptions in the current reactive scope, and returns its result.

This is useful when you need to access reactive data inside a reactive scope (like A) but do not want changes to that specific data to trigger a re-execute of the scope.

Note: You may also use unproxy to get to the raw underlying data structure, which can be used to similar effect.

<T, K>(target, key): T[K]

Executes a function or retrieves a value without creating subscriptions in the current reactive scope, and returns its result.

This is useful when you need to access reactive data inside a reactive scope (like A) but do not want changes to that specific data to trigger a re-execute of the scope.

Note: You may also use unproxy to get to the raw underlying data structure, which can be used to similar effect.

T extends object

K extends string | number | symbol

T

Either a function to execute, or an object (which may also be an Array or a Map) to index.

K

Optional key/index to use when target is an object.

T[K]

The result of the function call, or the value at target[key] when target is an object or target.get(key) when it’s a Map.

Peeking within observer

const $data = A.proxy({ a: 1, b: 2 });
A(() => {
// re-executes only when $data.a changes, because $data.b is peeked.
const b = A.peek(() => $data.b);
console.log(`A is ${$data.a}, B was ${b} when A changed.`);
});
$data.b = 3; // Does not trigger console.log
$data.a = 2; // Triggers console.log (logs "A is 2, B was 3 when A changed.")

<K, V>(target, key): V

Executes a function or retrieves a value without creating subscriptions in the current reactive scope, and returns its result.

This is useful when you need to access reactive data inside a reactive scope (like A) but do not want changes to that specific data to trigger a re-execute of the scope.

Note: You may also use unproxy to get to the raw underlying data structure, which can be used to similar effect.

K

V

Map<K, V>

Either a function to execute, or an object (which may also be an Array or a Map) to index.

K

Optional key/index to use when target is an object.

V

The result of the function call, or the value at target[key] when target is an object or target.get(key) when it’s a Map.

Peeking within observer

const $data = A.proxy({ a: 1, b: 2 });
A(() => {
// re-executes only when $data.a changes, because $data.b is peeked.
const b = A.peek(() => $data.b);
console.log(`A is ${$data.a}, B was ${b} when A changed.`);
});
$data.b = 3; // Does not trigger console.log
$data.a = 2; // Triggers console.log (logs "A is 2, B was 3 when A changed.")

<T>(target, key): T

Executes a function or retrieves a value without creating subscriptions in the current reactive scope, and returns its result.

This is useful when you need to access reactive data inside a reactive scope (like A) but do not want changes to that specific data to trigger a re-execute of the scope.

Note: You may also use unproxy to get to the raw underlying data structure, which can be used to similar effect.

T

T[]

Either a function to execute, or an object (which may also be an Array or a Map) to index.

number

Optional key/index to use when target is an object.

T

The result of the function call, or the value at target[key] when target is an object or target.get(key) when it’s a Map.

Peeking within observer

const $data = A.proxy({ a: 1, b: 2 });
A(() => {
// re-executes only when $data.a changes, because $data.b is peeked.
const b = A.peek(() => $data.b);
console.log(`A is ${$data.a}, B was ${b} when A changed.`);
});
$data.b = 3; // Does not trigger console.log
$data.a = 2; // Triggers console.log (logs "A is 2, B was 3 when A changed.")

<T>(target): T

Executes a function or retrieves a value without creating subscriptions in the current reactive scope, and returns its result.

This is useful when you need to access reactive data inside a reactive scope (like A) but do not want changes to that specific data to trigger a re-execute of the scope.

Note: You may also use unproxy to get to the raw underlying data structure, which can be used to similar effect.

T

() => T

Either a function to execute, or an object (which may also be an Array or a Map) to index.

T

The result of the function call, or the value at target[key] when target is an object or target.get(key) when it’s a Map.

Peeking within observer

const $data = A.proxy({ a: 1, b: 2 });
A(() => {
// re-executes only when $data.a changes, because $data.b is peeked.
const b = A.peek(() => $data.b);
console.log(`A is ${$data.a}, B was ${b} when A changed.`);
});
$data.b = 3; // Does not trigger console.log
$data.a = 2; // Triggers console.log (logs "A is 2, B was 3 when A changed.")

The result of the function call, or the value at target[key] when target is an object or target.get(key) when it’s a Map.

proxy: {<T>(target): PromiseProxy<T>; <T>(target): T extends number ? number : T extends string ? string : T extends boolean ? boolean : T[]; <T>(target): T; <T>(target): ValueRef<T extends number ? number : T extends string ? string : T extends boolean ? boolean : T>; }

Creates a reactive proxy around the given data.

Reading properties from the returned proxy within a reactive scope (like one created by A or derive) establishes a subscription. Modifying properties through the proxy will notify subscribed scopes, causing them to re-execute.

  • Plain objects, arrays, Maps, and Sets are wrapped in a standard JavaScript Proxy that intercepts property access and mutations, but otherwise works like the underlying data.
  • Primitives (string, number, boolean, null, undefined) are wrapped in an object { value: T } which is then proxied. Access the primitive via the .value property.
  • Promises are represented by proxied objects { busy: boolean, value?: T, error?: any }. Initially, busy is true. When the promise resolves, value is set and busy is set to false. If the promise is rejected, error is set and busy is also set to false.

Use unproxy to get the original underlying data back. By convention in the examples below, local variables that hold proxied values are prefixed with $.

<T>(target): PromiseProxy<T>

T extends unknown

Promise<T>

PromiseProxy<T>

<T>(target): T extends number ? number : T extends string ? string : T extends boolean ? boolean : T[]

T extends unknown

T[]

T extends number ? number : T extends string ? string : T extends boolean ? boolean : T[]

<T>(target): T

T extends object

T

T

<T>(target): ValueRef<T extends number ? number : T extends string ? string : T extends boolean ? boolean : T>

T extends unknown

T

ValueRef<T extends number ? number : T extends string ? string : T extends boolean ? boolean : T>

A reactive proxy wrapping the target data.

ref: <T, K>(target, index) => ValueRef<T[K]>

Creates a reactive reference ({ value: T }-like object) to a specific value within a proxied object or array.

This is primarily used for the bind property in A to create two-way data bindings with form elements, and for passing a reactive property to any of the A key-value pairs.

Reading ref.value accesses the property from the underlying proxy (and subscribes the current scope). Assigning to ref.value updates the property in the underlying proxy (triggering reactive updates).

Creates a reactive reference ({ value: T }-like object) to a specific value within a proxied object or array.

This is primarily used for the bind property in A to create two-way data bindings with form elements, and for passing a reactive property to any of the A key-value pairs.

Reading ref.value accesses the property from the underlying proxy (and subscribes the current scope). Assigning to ref.value updates the property in the underlying proxy (triggering reactive updates).

T extends TargetType

K extends string | number | symbol

T

The reactive proxy (created by proxy) containing the target property.

K

The key (for objects) or index (for arrays) of the property to reference.

ValueRef<T[K]>

A reference object with a value property linked to the specified proxy property.

const $formData = A.proxy({ color: 'orange', velocity: 42 });
// Usage with `bind`
A('input type=text bind=', A.ref($formData, 'color'));
// Usage as a dynamic property, causes a TextNode with just the name to be created and live-updated
A('p text="Selected color: " text=', A.ref($formData, 'color'), 'color:', A.ref($formData, 'color'));
// Changes are actually stored in $formData - this causes logs like `{color: "Blue", velocity 42}`
A(() => console.log($formData))

A reference object with a value property linked to the specified proxy property.

runQueue: () => void

Forces the immediate and synchronous execution of all pending reactive updates.

Normally, changes to observed data sources (like proxied objects or arrays) are processed asynchronously in a batch after a brief timeout (0ms). This function allows you to bypass the timeout and process the update queue immediately.

This can be useful in specific scenarios where you need the DOM to be updated synchronously.

This function is re-entrant, meaning it is safe to call runQueue from within a function that is itself being executed as part of an update cycle triggered by a previous (or the same) runQueue call.

Forces the immediate and synchronous execution of all pending reactive updates.

Normally, changes to observed data sources (like proxied objects or arrays) are processed asynchronously in a batch after a brief timeout (0ms). This function allows you to bypass the timeout and process the update queue immediately.

This can be useful in specific scenarios where you need the DOM to be updated synchronously.

This function is re-entrant, meaning it is safe to call runQueue from within a function that is itself being executed as part of an update cycle triggered by a previous (or the same) runQueue call.

void

const $data = A.proxy("before");
A('#', $data);
console.log(1, document.body.innerHTML); // before
// Make an update that should cause the DOM to change.
$data.value = "after";
// Normally, the DOM update would happen after a timeout.
// But this causes an immediate update:
A.runQueue();
console.log(2, document.body.innerHTML); // after

setErrorHandler: (handler?) => void

Sets a custom error handler function for errors that occur asynchronously within reactive scopes (e.g., during updates triggered by proxy changes in derive or A render functions).

The default handler logs the error to console.error and adds a simple ‘Error’ message div to the DOM at the location where the error occurred (if possible).

Your handler can provide custom logging, UI feedback, or suppress the default error message.

Sets a custom error handler function for errors that occur asynchronously within reactive scopes (e.g., during updates triggered by proxy changes in derive or A render functions).

The default handler logs the error to console.error and adds a simple ‘Error’ message div to the DOM at the location where the error occurred (if possible).

Your handler can provide custom logging, UI feedback, or suppress the default error message.

(error) => boolean

A function that accepts the Error object.

  • Return false to prevent adding an error message to the DOM.
  • Return true or undefined (or throw) to allow the error messages to be added to the DOM.

void

Custom Logging and Suppressing Default Message

A.setErrorHandler(error => {
console.warn('Aberdeen render error:', error.message);
// Log to error reporting service
// myErrorReporter.log(error);
try {
// Attempt to show a custom message in the UI
A('div#Oops, something went wrong!', errorClass);
} catch (e) {
// Ignore errors during error handling itself
}
return false; // Suppress default console log and DOM error message
});
// Styling for our custom error message
const errorClass = A.insertCss('background-color:#e31f00 display:inline-block color:white r:3px padding: 2px 4px;');
// Cause an error within a render scope.
A('div.box', () => {
// Will cause our error handler to insert an error message within the box
noSuchFunction();
})

setSpacingCssVars: (base, unit) => void

Initializes cssVars[0] through cssVars[12] with an exponential spacing scale.

The scale is calculated as 2^(n-3) * base, providing values from 0.25 * base to 512 * base.

Initializes cssVars[0] through cssVars[12] with an exponential spacing scale.

The scale is calculated as 2^(n-3) * base, providing values from 0.25 * base to 512 * base.

number = 1

The base size for the spacing scale that will apply to cssVars[3]. Every step up the scale will double this, while every step down will halve it. Defaults to 1.

string = 'rem'

The CSS unit to use, like ‘rem’, ‘em’, or ‘px’. Defaults to ‘rem’.

void

import A from 'aberdeen';
// Use default scale (0.25rem to 512rem)
A.setSpacingCssVars();
// Use custom base size
A.setSpacingCssVars(16, 'px'); // 4px to 8192px
// Use em units
A.setSpacingCssVars(1, 'em'); // 0.25em to 512em
// Show the last generated spacing values
A.onEach(A.cssVars, (value, key) => {
A(`div #${key}${value}`)
}, (value, key) => parseInt(key)); // Numeric sort

unmountAll: () => void

Removes all Aberdeen-managed DOM nodes and stops all active reactive scopes (created by mount, derive, A with functions, etc.).

This effectively cleans up the entire Aberdeen application state. Aside from in automated tests, there should probably be little reason to call this function.

Removes all Aberdeen-managed DOM nodes and stops all active reactive scopes (created by mount, derive, A with functions, etc.).

This effectively cleans up the entire Aberdeen application state. Aside from in automated tests, there should probably be little reason to call this function.

void

unproxy: <T>(target) => T

Returns the original, underlying data target from a reactive proxy created by proxy. If the input target is not a proxy, it is returned directly.

This is useful when you want to avoid triggering subscriptions during read operations or re-executes during write operations. Using peek is an alternative way to achieve this.

Returns the original, underlying data target from a reactive proxy created by proxy. If the input target is not a proxy, it is returned directly.

This is useful when you want to avoid triggering subscriptions during read operations or re-executes during write operations. Using peek is an alternative way to achieve this.

T

The type of the target.

T

A proxied object, array, or any other value.

T

The underlying (unproxied) data, or the input value if it wasn’t a proxy.

const $user = A.proxy({ name: 'Frank' });
const rawUser = A.unproxy($user);
// Log reactively
A(() => console.log('proxied', $user.name));
// The following will only ever log once, as we're not subscribing to any observable
A(() => console.log('unproxied', rawUser.name));
// This cause the first log to run again:
setTimeout(() => $user.name += '!', 1000);
// This doesn't cause any new logs:
setTimeout(() => rawUser.name += '?', 2000);
// Both $user and rawUser end up as `{name: 'Frank!?'}`
setTimeout(() => {
console.log('final proxied', $user)
console.log('final unproxied', rawUser)
}, 3000);

The underlying (unproxied) data, or the input value if it wasn’t a proxy.

Basic usage

import A from 'aberdeen';
const $state = A.proxy({ count: 0 });
A('div', () => {
A(`p#Count: ${$state.count}`);
A('button text=+ click=', () => $state.count++);
});