diff --git a/development/issues/closed/292.html b/development/issues/closed/292.html
new file mode 100644
index 0000000000000000000000000000000000000000..f7f19bb325257d2a8f165f83628099e85f6d2f58
--- /dev/null
+++ b/development/issues/closed/292.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>new transformer command for lists #292</title>
+    <script src="./292.mjs" type="module"></script>
+</head>
+
+<body>
+    <h1>new transformer command for lists #292</h1>
+    <p></p>
+    <ul>
+        <li><a href="https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/292">Issue #292</a></li>
+        <li><a href="/">Back to overview</a></li>
+    </ul>
+    <main>
+
+        <p> look at the console for the output</p>
+
+        <!-- Write your code here -->
+
+    </main>
+</body>
+
+</html>
diff --git a/development/issues/closed/292.mjs b/development/issues/closed/292.mjs
new file mode 100644
index 0000000000000000000000000000000000000000..9036e8c5881709da95830f6305ae4748e550cd27
--- /dev/null
+++ b/development/issues/closed/292.mjs
@@ -0,0 +1,26 @@
+/**
+* @file development/issues/open/292.mjs
+* @url https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/292
+* @description new transformer command for lists
+* @issue 292
+*/
+
+import "../../../source/components/style/property.pcss";
+import "../../../source/components/style/link.pcss";
+import "../../../source/components/style/color.pcss";
+import "../../../source/components/style/theme.pcss";
+import "../../../source/components/style/normalize.pcss";
+import "../../../source/components/style/typography.pcss";
+import {Transformer} from "../../../source/data/transformer.mjs";
+
+
+const transformer = new Transformer("listtoarray");
+console.log(transformer.run("1,2,3,4"));
+
+
+const transformer2 = new Transformer("arraytolist");
+console.log(transformer2.run([1,2,3,4]));
+
+
+const transformer3 = new Transformer("default::array");
+console.log(transformer3.run(undefined));
diff --git a/source/data/transformer.mjs b/source/data/transformer.mjs
index caeb744fa6f0a4c5de3f8ce440b42995aa29f430..ca88d015401b1e9664aa4a2991a63b56af36eece 100644
--- a/source/data/transformer.mjs
+++ b/source/data/transformer.mjs
@@ -23,6 +23,7 @@ import {
 } from "../i18n/translations.mjs";
 import {
 	validateFunction,
+	validateArray,
 	validateInteger,
 	validateObject,
 	validatePrimitive,
@@ -286,6 +287,30 @@ function transform(value) {
 			validateInteger(n);
 			return n;
 
+		case "to-array":
+		case "toarray":
+			if (isArray(value)) {
+				return value;
+			}
+
+			if (isObject(value)) {
+				return Object.values(value);
+			}
+
+			return [value];
+
+		case "listtoarray":
+		case "list-to-array":
+			validateString(value);
+			const listDel = args.shift() || ",";
+			return value.split(listDel);
+
+		case "arraytolist":
+		case "array-to-list":
+			validateArray(value);
+			const listDel2 = args.shift() || ",";
+			return value.join(listDel2);
+
 		case "to-json":
 		case "tojson":
 			return JSON.stringify(value);
@@ -398,7 +423,10 @@ function transform(value) {
 
 		case "debug":
 			if (isObject(console)) {
-				console.log(value);
+				console.groupCollapsed("Transformer Debug");
+				console.log("Value", value);
+				console.log("Transformer", this);
+				console.groupEnd();
 			}
 
 			return value;
@@ -581,6 +609,11 @@ function transform(value) {
 						defaultValue === "true" ||
 						defaultValue === "true"
 					);
+				case "array":
+					if (defaultValue === "") {
+						return [];
+					}
+					return defaultValue.split(",");
 				case "string":
 					return `${defaultValue}`;
 				case "object":
diff --git a/source/dom/updater.mjs b/source/dom/updater.mjs
index 303874215f536065782bd34b9af891bd5242051f..5aa2ce0f805d17f33dad1d2c8173324bd6cc95a0 100644
--- a/source/dom/updater.mjs
+++ b/source/dom/updater.mjs
@@ -12,43 +12,47 @@
  * SPDX-License-Identifier: AGPL-3.0
  */
 
-import {internalSymbol} from "../constants.mjs";
-import {diff} from "../data/diff.mjs";
-import {Pathfinder} from "../data/pathfinder.mjs";
-import {Pipe} from "../data/pipe.mjs";
+import { internalSymbol } from "../constants.mjs";
+import { diff } from "../data/diff.mjs";
+import { Pathfinder } from "../data/pathfinder.mjs";
+import { Pipe } from "../data/pipe.mjs";
 import {
-    ATTRIBUTE_ERRORMESSAGE,
-    ATTRIBUTE_UPDATER_ATTRIBUTES,
-    ATTRIBUTE_UPDATER_BIND,
-    ATTRIBUTE_UPDATER_BIND_TYPE,
-    ATTRIBUTE_UPDATER_INSERT,
-    ATTRIBUTE_UPDATER_INSERT_REFERENCE,
-    ATTRIBUTE_UPDATER_REMOVE,
-    ATTRIBUTE_UPDATER_REPLACE,
-    ATTRIBUTE_UPDATER_SELECT_THIS,
+	ATTRIBUTE_ERRORMESSAGE,
+	ATTRIBUTE_UPDATER_ATTRIBUTES,
+	ATTRIBUTE_UPDATER_BIND,
+	ATTRIBUTE_UPDATER_BIND_TYPE,
+	ATTRIBUTE_UPDATER_INSERT,
+	ATTRIBUTE_UPDATER_INSERT_REFERENCE,
+	ATTRIBUTE_UPDATER_REMOVE,
+	ATTRIBUTE_UPDATER_REPLACE,
+	ATTRIBUTE_UPDATER_SELECT_THIS,
 } from "./constants.mjs";
 
-import {Base} from "../types/base.mjs";
-import {isArray, isInteger, isString, isInstance, isIterable} from "../types/is.mjs";
-import {Observer} from "../types/observer.mjs";
-import {ProxyObserver} from "../types/proxyobserver.mjs";
-import {validateArray, validateInstance} from "../types/validate.mjs";
-import {clone} from "../util/clone.mjs";
-import {trimSpaces} from "../util/trimspaces.mjs";
-import {addAttributeToken, addToObjectLink} from "./attributes.mjs";
+import { Base } from "../types/base.mjs";
 import {
-    CustomElement,
-    updaterTransformerMethodsSymbol,
+	isArray,
+	isInteger,
+	isString,
+	isInstance,
+	isIterable,
+} from "../types/is.mjs";
+import { Observer } from "../types/observer.mjs";
+import { ProxyObserver } from "../types/proxyobserver.mjs";
+import { validateArray, validateInstance } from "../types/validate.mjs";
+import { clone } from "../util/clone.mjs";
+import { trimSpaces } from "../util/trimspaces.mjs";
+import { addAttributeToken, addToObjectLink } from "./attributes.mjs";
+import {
+	CustomElement,
+	updaterTransformerMethodsSymbol,
 } from "./customelement.mjs";
-import {findTargetElementFromEvent} from "./events.mjs";
-import {findDocumentTemplate} from "./template.mjs";
-import {getWindow} from "./util.mjs";
-import {DeadMansSwitch} from "../util/deadmansswitch.mjs";
-import {addErrorAttribute, removeErrorAttribute} from "./error.mjs";
-
-
-export {Updater, addObjectWithUpdaterToElement};
+import { findTargetElementFromEvent } from "./events.mjs";
+import { findDocumentTemplate } from "./template.mjs";
+import { getWindow } from "./util.mjs";
+import { DeadMansSwitch } from "../util/deadmansswitch.mjs";
+import { addErrorAttribute, removeErrorAttribute } from "./error.mjs";
 
+export { Updater, addObjectWithUpdaterToElement };
 
 /**
  * @private
@@ -81,190 +85,190 @@ const timerElementEventHandlerSymbol = Symbol("timerElementEventHandler");
  * @summary The updater class connects an object with the dom
  */
 class Updater extends Base {
-    /**
-     * @since 1.8.0
-     * @param {HTMLElement} element
-     * @param {object|ProxyObserver|undefined} subject
-     * @throws {TypeError} value is not a object
-     * @throws {TypeError} value is not an instance of HTMLElement
-     * @see {@link findDocumentTemplate}
-     */
-    constructor(element, subject) {
-        super();
-
-        /**
-         * @type {HTMLElement}
-         */
-        if (subject === undefined) subject = {};
-        if (!isInstance(subject, ProxyObserver)) {
-            subject = new ProxyObserver(subject);
-        }
-
-        this[internalSymbol] = {
-            element: validateInstance(element, HTMLElement),
-            last: {},
-            callbacks: new Map(),
-            eventTypes: ["keyup", "click", "change", "drop", "touchend", "input"],
-            subject: subject,
-        };
-
-        this[internalSymbol].callbacks.set(
-            "checkstate",
-            getCheckStateCallback.call(this),
-        );
-
-        this[internalSymbol].subject.attachObserver(
-            new Observer(() => {
-                const s = this[internalSymbol].subject.getRealSubject();
-
-                const diffResult = diff(this[internalSymbol].last, s);
-                this[internalSymbol].last = clone(s);
-
-                const promises = [];
-
-                for (const [, change] of Object.entries(diffResult)) {
-                    promises.push(
-                        new Promise((resolve, reject) => {
-                            getWindow().requestAnimationFrame(() => {
-                                try {
-                                    removeElement.call(this, change);
-                                    insertElement.call(this, change);
-                                    updateContent.call(this, change);
-                                    updateAttributes.call(this, change);
-
-                                    resolve();
-                                } catch (error) {
-                                    reject(error);
-                                }
-                            });
-                        }),
-                    );
-                }
-
-                return Promise.all(promises);
-            }),
-        );
-    }
-
-    /**
-     * Defaults: 'keyup', 'click', 'change', 'drop', 'touchend'
-     *
-     * @see {@link https://developer.mozilla.org/de/docs/Web/Events}
-     * @since 1.9.0
-     * @param {Array} types
-     * @return {Updater}
-     */
-    setEventTypes(types) {
-        this[internalSymbol].eventTypes = validateArray(types);
-        return this;
-    }
-
-    /**
-     * With this method, the eventlisteners are hooked in and the magic begins.
-     *
-     * ```js
-     * updater.run().then(() => {
-     *   updater.enableEventProcessing();
-     * });
-     * ```
-     *
-     * @since 1.9.0
-     * @return {Updater}
-     * @throws {Error} the bind argument must start as a value with a path
-     */
-    enableEventProcessing() {
-        this.disableEventProcessing();
-
-        for (const type of this[internalSymbol].eventTypes) {
-            // @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
-            this[internalSymbol].element.addEventListener(
-                type,
-                getControlEventHandler.call(this),
-                {
-                    capture: true,
-                    passive: true,
-                },
-            );
-        }
-
-        return this;
-    }
-
-    /**
-     * This method turns off the magic or who loves it more profane it removes the eventListener.
-     *
-     * @since 1.9.0
-     * @return {Updater}
-     */
-    disableEventProcessing() {
-        for (const type of this[internalSymbol].eventTypes) {
-            this[internalSymbol].element.removeEventListener(
-                type,
-                getControlEventHandler.call(this),
-            );
-        }
-
-        return this;
-    }
-
-    /**
-     * The run method must be called for the update to start working.
-     * The method ensures that changes are detected.
-     *
-     * ```js
-     * updater.run().then(() => {
-     *   updater.enableEventProcessing();
-     * });
-     * ```
-     *
-     * @summary Let the magic begin
-     * @return {Promise}
-     */
-    run() {
-        // the key __init__has no further meaning and is only
-        // used to create the diff for empty objects.
-        this[internalSymbol].last = {__init__: true};
-        return this[internalSymbol].subject.notifyObservers();
-    }
-
-    /**
-     * Gets the values of bound elements and changes them in subject
-     *
-     * @since 1.27.0
-     * @return {Monster.DOM.Updater}
-     */
-    retrieve() {
-        retrieveFromBindings.call(this);
-        return this;
-    }
-
-    /**
-     * If you have passed a ProxyObserver in the constructor, you will get the object that the ProxyObserver manages here.
-     * However, if you passed a simple object, here you will get a proxy for that object.
-     *
-     * For changes, the ProxyObserver must be used.
-     *
-     * @since 1.8.0
-     * @return {Proxy}
-     */
-    getSubject() {
-        return this[internalSymbol].subject.getSubject();
-    }
-
-    /**
-     * This method can be used to register commands that can be called via call: instruction.
-     * This can be used to provide a pipe with its own functionality.
-     *
-     * @param {string} name
-     * @param {function} callback
-     * @return {Transformer}
-     * @throws {TypeError} value is not a string
-     * @throws {TypeError} value is not a function
-     */
-    setCallback(name, callback) {
-        this[internalSymbol].callbacks.set(name, callback);
-        return this;
-    }
+	/**
+	 * @since 1.8.0
+	 * @param {HTMLElement} element
+	 * @param {object|ProxyObserver|undefined} subject
+	 * @throws {TypeError} value is not a object
+	 * @throws {TypeError} value is not an instance of HTMLElement
+	 * @see {@link findDocumentTemplate}
+	 */
+	constructor(element, subject) {
+		super();
+
+		/**
+		 * @type {HTMLElement}
+		 */
+		if (subject === undefined) subject = {};
+		if (!isInstance(subject, ProxyObserver)) {
+			subject = new ProxyObserver(subject);
+		}
+
+		this[internalSymbol] = {
+			element: validateInstance(element, HTMLElement),
+			last: {},
+			callbacks: new Map(),
+			eventTypes: ["keyup", "click", "change", "drop", "touchend", "input"],
+			subject: subject,
+		};
+
+		this[internalSymbol].callbacks.set(
+			"checkstate",
+			getCheckStateCallback.call(this),
+		);
+
+		this[internalSymbol].subject.attachObserver(
+			new Observer(() => {
+				const s = this[internalSymbol].subject.getRealSubject();
+
+				const diffResult = diff(this[internalSymbol].last, s);
+				this[internalSymbol].last = clone(s);
+
+				const promises = [];
+
+				for (const [, change] of Object.entries(diffResult)) {
+					promises.push(
+						new Promise((resolve, reject) => {
+							getWindow().requestAnimationFrame(() => {
+								try {
+									removeElement.call(this, change);
+									insertElement.call(this, change);
+									updateContent.call(this, change);
+									updateAttributes.call(this, change);
+
+									resolve();
+								} catch (error) {
+									reject(error);
+								}
+							});
+						}),
+					);
+				}
+
+				return Promise.all(promises);
+			}),
+		);
+	}
+
+	/**
+	 * Defaults: 'keyup', 'click', 'change', 'drop', 'touchend'
+	 *
+	 * @see {@link https://developer.mozilla.org/de/docs/Web/Events}
+	 * @since 1.9.0
+	 * @param {Array} types
+	 * @return {Updater}
+	 */
+	setEventTypes(types) {
+		this[internalSymbol].eventTypes = validateArray(types);
+		return this;
+	}
+
+	/**
+	 * With this method, the eventlisteners are hooked in and the magic begins.
+	 *
+	 * ```js
+	 * updater.run().then(() => {
+	 *   updater.enableEventProcessing();
+	 * });
+	 * ```
+	 *
+	 * @since 1.9.0
+	 * @return {Updater}
+	 * @throws {Error} the bind argument must start as a value with a path
+	 */
+	enableEventProcessing() {
+		this.disableEventProcessing();
+
+		for (const type of this[internalSymbol].eventTypes) {
+			// @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
+			this[internalSymbol].element.addEventListener(
+				type,
+				getControlEventHandler.call(this),
+				{
+					capture: true,
+					passive: true,
+				},
+			);
+		}
+
+		return this;
+	}
+
+	/**
+	 * This method turns off the magic or who loves it more profane it removes the eventListener.
+	 *
+	 * @since 1.9.0
+	 * @return {Updater}
+	 */
+	disableEventProcessing() {
+		for (const type of this[internalSymbol].eventTypes) {
+			this[internalSymbol].element.removeEventListener(
+				type,
+				getControlEventHandler.call(this),
+			);
+		}
+
+		return this;
+	}
+
+	/**
+	 * The run method must be called for the update to start working.
+	 * The method ensures that changes are detected.
+	 *
+	 * ```js
+	 * updater.run().then(() => {
+	 *   updater.enableEventProcessing();
+	 * });
+	 * ```
+	 *
+	 * @summary Let the magic begin
+	 * @return {Promise}
+	 */
+	run() {
+		// the key __init__has no further meaning and is only
+		// used to create the diff for empty objects.
+		this[internalSymbol].last = { __init__: true };
+		return this[internalSymbol].subject.notifyObservers();
+	}
+
+	/**
+	 * Gets the values of bound elements and changes them in subject
+	 *
+	 * @since 1.27.0
+	 * @return {Monster.DOM.Updater}
+	 */
+	retrieve() {
+		retrieveFromBindings.call(this);
+		return this;
+	}
+
+	/**
+	 * If you have passed a ProxyObserver in the constructor, you will get the object that the ProxyObserver manages here.
+	 * However, if you passed a simple object, here you will get a proxy for that object.
+	 *
+	 * For changes, the ProxyObserver must be used.
+	 *
+	 * @since 1.8.0
+	 * @return {Proxy}
+	 */
+	getSubject() {
+		return this[internalSymbol].subject.getSubject();
+	}
+
+	/**
+	 * This method can be used to register commands that can be called via call: instruction.
+	 * This can be used to provide a pipe with its own functionality.
+	 *
+	 * @param {string} name
+	 * @param {function} callback
+	 * @return {Transformer}
+	 * @throws {TypeError} value is not a string
+	 * @throws {TypeError} value is not a function
+	 */
+	setCallback(name, callback) {
+		this[internalSymbol].callbacks.set(name, callback);
+		return this;
+	}
 }
 
 /**
@@ -275,20 +279,20 @@ class Updater extends Base {
  * @this Updater
  */
 function getCheckStateCallback() {
-    return function (current) {
-        // this is a reference to the current object (therefore no array function here)
-        if (this instanceof HTMLInputElement) {
-            if (["radio", "checkbox"].indexOf(this.type) !== -1) {
-                return `${this.value}` === `${current}` ? "true" : undefined;
-            }
-        } else if (this instanceof HTMLOptionElement) {
-            if (isArray(current) && current.indexOf(this.value) !== -1) {
-                return "true";
-            }
-
-            return undefined;
-        }
-    };
+	return function (current) {
+		// this is a reference to the current object (therefore no array function here)
+		if (this instanceof HTMLInputElement) {
+			if (["radio", "checkbox"].indexOf(this.type) !== -1) {
+				return `${this.value}` === `${current}` ? "true" : undefined;
+			}
+		} else if (this instanceof HTMLOptionElement) {
+			if (isArray(current) && current.indexOf(this.value) !== -1) {
+				return "true";
+			}
+
+			return undefined;
+		}
+	};
 }
 
 /**
@@ -303,41 +307,41 @@ const symbol = Symbol("@schukai/monster/updater@@EventHandler");
  * @throws {Error} the bind argument must start as a value with a path
  */
 function getControlEventHandler() {
-    if (this[symbol]) {
-        return this[symbol];
-    }
-
-    /**
-     * @throws {Error} the bind argument must start as a value with a path.
-     * @throws {Error} unsupported object
-     * @param {Event} event
-     */
-    this[symbol] = (event) => {
-        const element = findTargetElementFromEvent(event, ATTRIBUTE_UPDATER_BIND);
-
-        if (element === undefined) {
-            return;
-        }
-
-        if (this[timerElementEventHandlerSymbol] instanceof DeadMansSwitch) {
-            try {
-                this[timerElementEventHandlerSymbol].touch();
-                return;
-            } catch (e) {
-                delete this[timerElementEventHandlerSymbol];
-            }
-        }
-
-        this[timerElementEventHandlerSymbol] = new DeadMansSwitch(50, () => {
-            try {
-                retrieveAndSetValue.call(this, element);
-            } catch (e) {
-                addErrorAttribute(element, e);
-            }
-        });
-    };
-
-    return this[symbol];
+	if (this[symbol]) {
+		return this[symbol];
+	}
+
+	/**
+	 * @throws {Error} the bind argument must start as a value with a path.
+	 * @throws {Error} unsupported object
+	 * @param {Event} event
+	 */
+	this[symbol] = (event) => {
+		const element = findTargetElementFromEvent(event, ATTRIBUTE_UPDATER_BIND);
+
+		if (element === undefined) {
+			return;
+		}
+
+		if (this[timerElementEventHandlerSymbol] instanceof DeadMansSwitch) {
+			try {
+				this[timerElementEventHandlerSymbol].touch();
+				return;
+			} catch (e) {
+				delete this[timerElementEventHandlerSymbol];
+			}
+		}
+
+		this[timerElementEventHandlerSymbol] = new DeadMansSwitch(50, () => {
+			try {
+				retrieveAndSetValue.call(this, element);
+			} catch (e) {
+				addErrorAttribute(element, e);
+			}
+		});
+	};
+
+	return this[symbol];
 }
 
 /**
@@ -347,186 +351,184 @@ function getControlEventHandler() {
  * @private
  */
 function retrieveAndSetValue(element) {
-    const pathfinder = new Pathfinder(this[internalSymbol].subject.getSubject());
-
-    let path = element.getAttribute(ATTRIBUTE_UPDATER_BIND);
-    if (path === null)
-        throw new Error("the bind argument must start as a value with a path");
-
-    if (path.indexOf("path:") !== 0) {
-        throw new Error("the bind argument must start as a value with a path");
-    }
-
-    path = path.substring(5); // remove path: from the string
-
-    let value;
-
-    if (element instanceof HTMLInputElement) {
-        switch (element.type) {
-            case "checkbox":
-                value = element.checked ? element.value : undefined;
-                break;
-            default:
-                value = element.value;
-                break;
-        }
-    } else if (element instanceof HTMLTextAreaElement) {
-        value = element.value;
-    } else if (element instanceof HTMLSelectElement) {
-        switch (element.type) {
-            case "select-one":
-                value = element.value;
-                break;
-            case "select-multiple":
-                value = element.value;
-
-                let options = element?.selectedOptions;
-                if (options === undefined)
-                    options = element.querySelectorAll(":scope option:checked");
-                value = Array.from(options).map(({value}) => value);
-
-                break;
-        }
-
-        // values from custom elements
-    } else if (
-        (element?.constructor?.prototype &&
-            !!Object.getOwnPropertyDescriptor(
-                element.constructor.prototype,
-                "value",
-            )?.["get"]) ||
-        "value" in element
-    ) {
-        value = element?.["value"];
-    } else {
-        throw new Error("unsupported object");
-    }
-
-    const type = element.getAttribute(ATTRIBUTE_UPDATER_BIND_TYPE);
-    switch (type) {
-
-        case "integer?":
-        case "int?":
-        case "number?":
-            value = Number(value);
-            if (isNaN(value)||0===value) {
-                value = undefined;
-            }
-            break;
-
-        case "number":
-        case "int":
-        case "float":
-        case "integer":
-            value = Number(value);
-            if (isNaN(value)) {
-                value = 0;
-            }
-            break;
-        case "boolean":
-        case "bool":
-        case "checkbox":
-            value = value === "true" || value === "1" || value === "on" || value === true;
-            break;
-
-        case "string[]":
-            if (isString(value)) {
-
-                if (value.trim() === "") {
-                    value = [];
-                } else {
-                    value = value.split(",").map((v) => `${v}`);
-                }
-            } else if (isInteger(value)) {
-                value = [`${value}`];
-            } else if (value === undefined || value === null) {
-                value = [];
-            } else if (isArray(value)) {
-                value = value.map((v) => `${v}`);
-            } else {
-                throw new Error("unsupported value");
-            }
-
-            break;
-
-        case "int[]":
-        case "integer[]":
-
-            if (isString(value)) {
-
-                if (value.trim() === "") {
-                    value = [];
-                } else {
-                    value = value.split(",").map((v) => {
-                        try {
-                            return parseInt(v, 10);
-                        } catch (e) {
-                        }
-                        return -1;
-                    }).filter((v) => v !== -1);
-                }
-
-            } else if (isInteger(value)) {
-                value = [value];
-            } else if (value === undefined || value === null) {
-                value = [];
-            } else if (isArray(value)) {
-                value = value.split(",").map((v) => {
-                    try {
-                        return parseInt(v, 10);
-                    } catch (e) {
-                    }
-                    return -1;
-                }).filter((v) => v !== -1);
-            } else {
-                throw new Error("unsupported value");
-            }
-
-            break;
-        case "[]":
-        case "array":
-        case "list":
-
-            if (isString(value)) {
-                if (value.trim() === "") {
-                    value = [];
-                } else {
-                    value = value.split(",");
-                }
-            } else if (isInteger(value)) {
-                value = [value];
-            } else if (value === undefined || value === null) {
-                value = [];
-            } else if (isArray(value)) {
-                // nothing to do
-            } else {
-                throw new Error("unsupported value for array");
-            }
-            break;
-        case "object":
-        case "json":
-
-            if (isString(value)) {
-                value = JSON.parse(value);
-            } else {
-                throw new Error("unsupported value for object");
-            }
-
-            break;
-        default:
-            break;
-    }
-
-    const copy = clone(this[internalSymbol].subject.getRealSubject());
-
-    const pf = new Pathfinder(copy);
-    pf.setVia(path, value);
-
-    const diffResult = diff(copy, this[internalSymbol].subject.getRealSubject());
-
-    if (diffResult.length > 0) {
-        pathfinder.setVia(path, value);
-    }
+	const pathfinder = new Pathfinder(this[internalSymbol].subject.getSubject());
+
+	let path = element.getAttribute(ATTRIBUTE_UPDATER_BIND);
+	if (path === null)
+		throw new Error("the bind argument must start as a value with a path");
+
+	if (path.indexOf("path:") !== 0) {
+		throw new Error("the bind argument must start as a value with a path");
+	}
+
+	path = path.substring(5); // remove path: from the string
+
+	let value;
+
+	if (element instanceof HTMLInputElement) {
+		switch (element.type) {
+			case "checkbox":
+				value = element.checked ? element.value : undefined;
+				break;
+			default:
+				value = element.value;
+				break;
+		}
+	} else if (element instanceof HTMLTextAreaElement) {
+		value = element.value;
+	} else if (element instanceof HTMLSelectElement) {
+		switch (element.type) {
+			case "select-one":
+				value = element.value;
+				break;
+			case "select-multiple":
+				value = element.value;
+
+				let options = element?.selectedOptions;
+				if (options === undefined)
+					options = element.querySelectorAll(":scope option:checked");
+				value = Array.from(options).map(({ value }) => value);
+
+				break;
+		}
+
+		// values from custom elements
+	} else if (
+		(element?.constructor?.prototype &&
+			!!Object.getOwnPropertyDescriptor(
+				element.constructor.prototype,
+				"value",
+			)?.["get"]) ||
+		"value" in element
+	) {
+		value = element?.["value"];
+	} else {
+		throw new Error("unsupported object");
+	}
+
+	const type = element.getAttribute(ATTRIBUTE_UPDATER_BIND_TYPE);
+	switch (type) {
+		case "integer?":
+		case "int?":
+		case "number?":
+			value = Number(value);
+			if (isNaN(value) || 0 === value) {
+				value = undefined;
+			}
+			break;
+
+		case "number":
+		case "int":
+		case "float":
+		case "integer":
+			value = Number(value);
+			if (isNaN(value)) {
+				value = 0;
+			}
+			break;
+		case "boolean":
+		case "bool":
+		case "checkbox":
+			value =
+				value === "true" || value === "1" || value === "on" || value === true;
+			break;
+
+		case "string[]":
+			if (isString(value)) {
+				if (value.trim() === "") {
+					value = [];
+				} else {
+					value = value.split(",").map((v) => `${v}`);
+				}
+			} else if (isInteger(value)) {
+				value = [`${value}`];
+			} else if (value === undefined || value === null) {
+				value = [];
+			} else if (isArray(value)) {
+				value = value.map((v) => `${v}`);
+			} else {
+				throw new Error("unsupported value");
+			}
+
+			break;
+
+		case "int[]":
+		case "integer[]":
+			if (isString(value)) {
+				if (value.trim() === "") {
+					value = [];
+				} else {
+					value = value
+						.split(",")
+						.map((v) => {
+							try {
+								return parseInt(v, 10);
+							} catch (e) {}
+							return -1;
+						})
+						.filter((v) => v !== -1);
+				}
+			} else if (isInteger(value)) {
+				value = [value];
+			} else if (value === undefined || value === null) {
+				value = [];
+			} else if (isArray(value)) {
+				value = value
+					.split(",")
+					.map((v) => {
+						try {
+							return parseInt(v, 10);
+						} catch (e) {}
+						return -1;
+					})
+					.filter((v) => v !== -1);
+			} else {
+				throw new Error("unsupported value");
+			}
+
+			break;
+		case "[]":
+		case "array":
+		case "list":
+			if (isString(value)) {
+				if (value.trim() === "") {
+					value = [];
+				} else {
+					value = value.split(",");
+				}
+			} else if (isInteger(value)) {
+				value = [value];
+			} else if (value === undefined || value === null) {
+				value = [];
+			} else if (isArray(value)) {
+				// nothing to do
+			} else {
+				throw new Error("unsupported value for array");
+			}
+			break;
+		case "object":
+		case "json":
+			if (isString(value)) {
+				value = JSON.parse(value);
+			} else {
+				throw new Error("unsupported value for object");
+			}
+
+			break;
+		default:
+			break;
+	}
+
+	const copy = clone(this[internalSymbol].subject.getRealSubject());
+
+	const pf = new Pathfinder(copy);
+	pf.setVia(path, value);
+
+	const diffResult = diff(copy, this[internalSymbol].subject.getRealSubject());
+
+	if (diffResult.length > 0) {
+		pathfinder.setVia(path, value);
+	}
 }
 
 /**
@@ -536,15 +538,15 @@ function retrieveAndSetValue(element) {
  * @private
  */
 function retrieveFromBindings() {
-    if (this[internalSymbol].element.matches(`[${ATTRIBUTE_UPDATER_BIND}]`)) {
-        retrieveAndSetValue.call(this, this[internalSymbol].element);
-    }
-
-    for (const [, element] of this[internalSymbol].element
-        .querySelectorAll(`[${ATTRIBUTE_UPDATER_BIND}]`)
-        .entries()) {
-        retrieveAndSetValue.call(this, element);
-    }
+	if (this[internalSymbol].element.matches(`[${ATTRIBUTE_UPDATER_BIND}]`)) {
+		retrieveAndSetValue.call(this, this[internalSymbol].element);
+	}
+
+	for (const [, element] of this[internalSymbol].element
+		.querySelectorAll(`[${ATTRIBUTE_UPDATER_BIND}]`)
+		.entries()) {
+		retrieveAndSetValue.call(this, element);
+	}
 }
 
 /**
@@ -555,11 +557,11 @@ function retrieveFromBindings() {
  * @return {void}
  */
 function removeElement(change) {
-    for (const [, element] of this[internalSymbol].element
-        .querySelectorAll(`:scope [${ATTRIBUTE_UPDATER_REMOVE}]`)
-        .entries()) {
-        element.parentNode.removeChild(element);
-    }
+	for (const [, element] of this[internalSymbol].element
+		.querySelectorAll(`:scope [${ATTRIBUTE_UPDATER_REMOVE}]`)
+		.entries()) {
+		element.parentNode.removeChild(element);
+	}
 }
 
 /**
@@ -575,128 +577,128 @@ function removeElement(change) {
  * @this Updater
  */
 function insertElement(change) {
-    const subject = this[internalSymbol].subject.getRealSubject();
+	const subject = this[internalSymbol].subject.getRealSubject();
 
-    const mem = new WeakSet();
-    let wd = 0;
+	const mem = new WeakSet();
+	let wd = 0;
 
-    const container = this[internalSymbol].element;
+	const container = this[internalSymbol].element;
 
-    while (true) {
-        let found = false;
-        wd++;
-
-        const p = clone(change?.["path"]);
-        if (!isArray(p)) return;
-
-        while (p.length > 0) {
-            const current = p.join(".");
-
-            let iterator = new Set();
-            const query = `[${ATTRIBUTE_UPDATER_INSERT}*="path:${current}"]`;
-
-            const e = container.querySelectorAll(query);
-
-            if (e.length > 0) {
-                iterator = new Set([...e]);
-            }
-
-            if (container.matches(query)) {
-                iterator.add(container);
-            }
-
-            for (const [, containerElement] of iterator.entries()) {
-                if (mem.has(containerElement)) continue;
-                mem.add(containerElement);
-
-                found = true;
-
-                const attributes = containerElement.getAttribute(
-                    ATTRIBUTE_UPDATER_INSERT,
-                );
-                if (attributes === null) continue;
-
-                const def = trimSpaces(attributes);
-                const i = def.indexOf(" ");
-                const key = trimSpaces(def.substr(0, i));
-                const refPrefix = `${key}-`;
-                const cmd = trimSpaces(def.substr(i));
-
-                // this case is actually excluded by the query but is nevertheless checked again here
-                if (cmd.indexOf("|") > 0) {
-                    throw new Error("pipes are not allowed when cloning a node.");
-                }
-
-                const pipe = new Pipe(cmd);
-                this[internalSymbol].callbacks.forEach((f, n) => {
-                    pipe.setCallback(n, f);
-                });
-
-                let value;
-                try {
-                    containerElement.removeAttribute(ATTRIBUTE_ERRORMESSAGE);
-                    value = pipe.run(subject);
-                } catch (e) {
-                    addErrorAttribute(containerElement, e);
-                }
-
-                const dataPath = cmd.split(":").pop();
-
-                let insertPoint;
-                if (containerElement.hasChildNodes()) {
-                    insertPoint = containerElement.lastChild;
-                }
-
-                if (!isIterable(value)) {
-                    throw new Error("the value is not iterable");
-                }
-
-                const available = new Set();
-
-                for (const [i] of Object.entries(value)) {
-                    const ref = refPrefix + i;
-                    const currentPath = `${dataPath}.${i}`;
-
-                    available.add(ref);
-                    const refElement = containerElement.querySelector(
-                        `[${ATTRIBUTE_UPDATER_INSERT_REFERENCE}="${ref}"]`,
-                    );
-
-                    if (refElement instanceof HTMLElement) {
-                        insertPoint = refElement;
-                        continue;
-                    }
-
-                    appendNewDocumentFragment(containerElement, key, ref, currentPath);
-                }
-
-                const nodes = containerElement.querySelectorAll(
-                    `[${ATTRIBUTE_UPDATER_INSERT_REFERENCE}*="${refPrefix}"]`,
-                );
-
-                for (const [, node] of Object.entries(nodes)) {
-                    if (
-                        !available.has(
-                            node.getAttribute(ATTRIBUTE_UPDATER_INSERT_REFERENCE),
-                        )
-                    ) {
-                        try {
-                            containerElement.removeChild(node);
-                        } catch (e) {
-                            addErrorAttribute(containerElement, e);
-                        }
-                    }
-                }
-            }
-
-            p.pop();
-        }
-
-        if (found === false) break;
-        if (wd++ > 200) {
-            throw new Error("the maximum depth for the recursion is reached.");
-        }
-    }
+	while (true) {
+		let found = false;
+		wd++;
+
+		const p = clone(change?.["path"]);
+		if (!isArray(p)) return;
+
+		while (p.length > 0) {
+			const current = p.join(".");
+
+			let iterator = new Set();
+			const query = `[${ATTRIBUTE_UPDATER_INSERT}*="path:${current}"]`;
+
+			const e = container.querySelectorAll(query);
+
+			if (e.length > 0) {
+				iterator = new Set([...e]);
+			}
+
+			if (container.matches(query)) {
+				iterator.add(container);
+			}
+
+			for (const [, containerElement] of iterator.entries()) {
+				if (mem.has(containerElement)) continue;
+				mem.add(containerElement);
+
+				found = true;
+
+				const attributes = containerElement.getAttribute(
+					ATTRIBUTE_UPDATER_INSERT,
+				);
+				if (attributes === null) continue;
+
+				const def = trimSpaces(attributes);
+				const i = def.indexOf(" ");
+				const key = trimSpaces(def.substr(0, i));
+				const refPrefix = `${key}-`;
+				const cmd = trimSpaces(def.substr(i));
+
+				// this case is actually excluded by the query but is nevertheless checked again here
+				if (cmd.indexOf("|") > 0) {
+					throw new Error("pipes are not allowed when cloning a node.");
+				}
+
+				const pipe = new Pipe(cmd);
+				this[internalSymbol].callbacks.forEach((f, n) => {
+					pipe.setCallback(n, f);
+				});
+
+				let value;
+				try {
+					containerElement.removeAttribute(ATTRIBUTE_ERRORMESSAGE);
+					value = pipe.run(subject);
+				} catch (e) {
+					addErrorAttribute(containerElement, e);
+				}
+
+				const dataPath = cmd.split(":").pop();
+
+				let insertPoint;
+				if (containerElement.hasChildNodes()) {
+					insertPoint = containerElement.lastChild;
+				}
+
+				if (!isIterable(value)) {
+					throw new Error("the value is not iterable");
+				}
+
+				const available = new Set();
+
+				for (const [i] of Object.entries(value)) {
+					const ref = refPrefix + i;
+					const currentPath = `${dataPath}.${i}`;
+
+					available.add(ref);
+					const refElement = containerElement.querySelector(
+						`[${ATTRIBUTE_UPDATER_INSERT_REFERENCE}="${ref}"]`,
+					);
+
+					if (refElement instanceof HTMLElement) {
+						insertPoint = refElement;
+						continue;
+					}
+
+					appendNewDocumentFragment(containerElement, key, ref, currentPath);
+				}
+
+				const nodes = containerElement.querySelectorAll(
+					`[${ATTRIBUTE_UPDATER_INSERT_REFERENCE}*="${refPrefix}"]`,
+				);
+
+				for (const [, node] of Object.entries(nodes)) {
+					if (
+						!available.has(
+							node.getAttribute(ATTRIBUTE_UPDATER_INSERT_REFERENCE),
+						)
+					) {
+						try {
+							containerElement.removeChild(node);
+						} catch (e) {
+							addErrorAttribute(containerElement, e);
+						}
+					}
+				}
+			}
+
+			p.pop();
+		}
+
+		if (found === false) break;
+		if (wd++ > 200) {
+			throw new Error("the maximum depth for the recursion is reached.");
+		}
+	}
 }
 
 /**
@@ -711,17 +713,17 @@ function insertElement(change) {
  * @throws {Error} no template was found with the specified key.
  */
 function appendNewDocumentFragment(container, key, ref, path) {
-    const template = findDocumentTemplate(key, container);
+	const template = findDocumentTemplate(key, container);
 
-    const nodes = template.createDocumentFragment();
-    for (const [, node] of Object.entries(nodes.childNodes)) {
-        if (node instanceof HTMLElement) {
-            applyRecursive(node, key, path);
-            node.setAttribute(ATTRIBUTE_UPDATER_INSERT_REFERENCE, ref);
-        }
+	const nodes = template.createDocumentFragment();
+	for (const [, node] of Object.entries(nodes.childNodes)) {
+		if (node instanceof HTMLElement) {
+			applyRecursive(node, key, path);
+			node.setAttribute(ATTRIBUTE_UPDATER_INSERT_REFERENCE, ref);
+		}
 
-        container.appendChild(node);
-    }
+		container.appendChild(node);
+	}
 }
 
 /**
@@ -734,32 +736,31 @@ function appendNewDocumentFragment(container, key, ref, path) {
  * @return {void}
  */
 function applyRecursive(node, key, path) {
-    if (!(node instanceof HTMLElement)) {
-        return
-    }
-
-    if (node.hasAttribute(ATTRIBUTE_UPDATER_REPLACE)) {
-        const value = node.getAttribute(ATTRIBUTE_UPDATER_REPLACE);
-        node.setAttribute(
-            ATTRIBUTE_UPDATER_REPLACE,
-            value.replaceAll(`path:${key}`, `path:${path}`),
-        );
-    }
-
-    if (node.hasAttribute(ATTRIBUTE_UPDATER_ATTRIBUTES)) {
-        const value = node.getAttribute(ATTRIBUTE_UPDATER_ATTRIBUTES);
-        node.setAttribute(
-            ATTRIBUTE_UPDATER_ATTRIBUTES,
-            value.replaceAll(`path:${key}`, `path:${path}`),
-        );
-    }
-
-    for (const [, child] of Object.entries(node.childNodes)) {
-        if (child instanceof HTMLElement) {
-            applyRecursive(child, key, path);
-        }
-    }
-
+	if (!(node instanceof HTMLElement)) {
+		return;
+	}
+
+	if (node.hasAttribute(ATTRIBUTE_UPDATER_REPLACE)) {
+		const value = node.getAttribute(ATTRIBUTE_UPDATER_REPLACE);
+		node.setAttribute(
+			ATTRIBUTE_UPDATER_REPLACE,
+			value.replaceAll(`path:${key}`, `path:${path}`),
+		);
+	}
+
+	if (node.hasAttribute(ATTRIBUTE_UPDATER_ATTRIBUTES)) {
+		const value = node.getAttribute(ATTRIBUTE_UPDATER_ATTRIBUTES);
+		node.setAttribute(
+			ATTRIBUTE_UPDATER_ATTRIBUTES,
+			value.replaceAll(`path:${key}`, `path:${path}`),
+		);
+	}
+
+	for (const [, child] of Object.entries(node.childNodes)) {
+		if (child instanceof HTMLElement) {
+			applyRecursive(child, key, path);
+		}
+	}
 }
 
 /**
@@ -771,19 +772,19 @@ function applyRecursive(node, key, path) {
  * @this Updater
  */
 function updateContent(change) {
-    const subject = this[internalSymbol].subject.getRealSubject();
-
-    const p = clone(change?.["path"]);
-    runUpdateContent.call(this, this[internalSymbol].element, p, subject);
-
-    const slots = this[internalSymbol].element.querySelectorAll("slot");
-    if (slots.length > 0) {
-        for (const [, slot] of Object.entries(slots)) {
-            for (const [, element] of Object.entries(slot.assignedNodes())) {
-                runUpdateContent.call(this, element, p, subject);
-            }
-        }
-    }
+	const subject = this[internalSymbol].subject.getRealSubject();
+
+	const p = clone(change?.["path"]);
+	runUpdateContent.call(this, this[internalSymbol].element, p, subject);
+
+	const slots = this[internalSymbol].element.querySelectorAll("slot");
+	if (slots.length > 0) {
+		for (const [, slot] of Object.entries(slots)) {
+			for (const [, element] of Object.entries(slot.assignedNodes())) {
+				runUpdateContent.call(this, element, p, subject);
+			}
+		}
+	}
 }
 
 /**
@@ -796,64 +797,64 @@ function updateContent(change) {
  * @return {void}
  */
 function runUpdateContent(container, parts, subject) {
-    if (!isArray(parts)) return;
-    if (!(container instanceof HTMLElement)) return;
-    parts = clone(parts);
-
-    const mem = new WeakSet();
-
-    while (parts.length > 0) {
-        const current = parts.join(".");
-        parts.pop();
-
-        // Unfortunately, static data is always changed as well, since it is not possible to react to changes here.
-        const query = `[${ATTRIBUTE_UPDATER_REPLACE}^="path:${current}"], [${ATTRIBUTE_UPDATER_REPLACE}^="static:"], [${ATTRIBUTE_UPDATER_REPLACE}^="i18n:"]`;
-        const e = container.querySelectorAll(`${query}`);
-
-        const iterator = new Set([...e]);
-
-        if (container.matches(query)) {
-            iterator.add(container);
-        }
-
-        /**
-         * @type {HTMLElement}
-         */
-        for (const [element] of iterator.entries()) {
-            if (mem.has(element)) return;
-            mem.add(element);
-
-            const attributes = element.getAttribute(ATTRIBUTE_UPDATER_REPLACE);
-            const cmd = trimSpaces(attributes);
-
-            const pipe = new Pipe(cmd);
-            this[internalSymbol].callbacks.forEach((f, n) => {
-                pipe.setCallback(n, f);
-            });
-
-            let value;
-            try {
-                element.removeAttribute(ATTRIBUTE_ERRORMESSAGE);
-                value = pipe.run(subject);
-            } catch (e) {
-                element.setAttribute(ATTRIBUTE_ERRORMESSAGE, e.message);
-            }
-
-            if (value instanceof HTMLElement) {
-                while (element.firstChild) {
-                    element.removeChild(element.firstChild);
-                }
-
-                try {
-                    element.appendChild(value);
-                } catch (e) {
-                    addErrorAttribute(element, e);
-                }
-            } else {
-                element.innerHTML = value;
-            }
-        }
-    }
+	if (!isArray(parts)) return;
+	if (!(container instanceof HTMLElement)) return;
+	parts = clone(parts);
+
+	const mem = new WeakSet();
+
+	while (parts.length > 0) {
+		const current = parts.join(".");
+		parts.pop();
+
+		// Unfortunately, static data is always changed as well, since it is not possible to react to changes here.
+		const query = `[${ATTRIBUTE_UPDATER_REPLACE}^="path:${current}"], [${ATTRIBUTE_UPDATER_REPLACE}^="static:"], [${ATTRIBUTE_UPDATER_REPLACE}^="i18n:"]`;
+		const e = container.querySelectorAll(`${query}`);
+
+		const iterator = new Set([...e]);
+
+		if (container.matches(query)) {
+			iterator.add(container);
+		}
+
+		/**
+		 * @type {HTMLElement}
+		 */
+		for (const [element] of iterator.entries()) {
+			if (mem.has(element)) return;
+			mem.add(element);
+
+			const attributes = element.getAttribute(ATTRIBUTE_UPDATER_REPLACE);
+			const cmd = trimSpaces(attributes);
+
+			const pipe = new Pipe(cmd);
+			this[internalSymbol].callbacks.forEach((f, n) => {
+				pipe.setCallback(n, f);
+			});
+
+			let value;
+			try {
+				element.removeAttribute(ATTRIBUTE_ERRORMESSAGE);
+				value = pipe.run(subject);
+			} catch (e) {
+				element.setAttribute(ATTRIBUTE_ERRORMESSAGE, e.message);
+			}
+
+			if (value instanceof HTMLElement) {
+				while (element.firstChild) {
+					element.removeChild(element.firstChild);
+				}
+
+				try {
+					element.appendChild(value);
+				} catch (e) {
+					addErrorAttribute(element, e);
+				}
+			} else {
+				element.innerHTML = value;
+			}
+		}
+	}
 }
 
 /**
@@ -863,9 +864,9 @@ function runUpdateContent(container, parts, subject) {
  * @return {void}
  */
 function updateAttributes(change) {
-    const subject = this[internalSymbol].subject.getRealSubject();
-    const p = clone(change?.["path"]);
-    runUpdateAttributes.call(this, this[internalSymbol].element, p, subject);
+	const subject = this[internalSymbol].subject.getRealSubject();
+	const p = clone(change?.["path"]);
+	runUpdateAttributes.call(this, this[internalSymbol].element, p, subject);
 }
 
 /**
@@ -877,70 +878,70 @@ function updateAttributes(change) {
  * @this Updater
  */
 function runUpdateAttributes(container, parts, subject) {
-    if (!isArray(parts)) return;
-    parts = clone(parts);
+	if (!isArray(parts)) return;
+	parts = clone(parts);
 
-    const mem = new WeakSet();
+	const mem = new WeakSet();
 
-    while (parts.length > 0) {
-        const current = parts.join(".");
-        parts.pop();
+	while (parts.length > 0) {
+		const current = parts.join(".");
+		parts.pop();
 
-        let iterator = new Set();
+		let iterator = new Set();
 
-        const query = `[${ATTRIBUTE_UPDATER_SELECT_THIS}][${ATTRIBUTE_UPDATER_ATTRIBUTES}], [${ATTRIBUTE_UPDATER_ATTRIBUTES}*="path:${current}"], [${ATTRIBUTE_UPDATER_ATTRIBUTES}^="static:"], [${ATTRIBUTE_UPDATER_ATTRIBUTES}^="i18n:"]`;
+		const query = `[${ATTRIBUTE_UPDATER_SELECT_THIS}][${ATTRIBUTE_UPDATER_ATTRIBUTES}], [${ATTRIBUTE_UPDATER_ATTRIBUTES}*="path:${current}"], [${ATTRIBUTE_UPDATER_ATTRIBUTES}^="static:"], [${ATTRIBUTE_UPDATER_ATTRIBUTES}^="i18n:"]`;
 
-        const e = container.querySelectorAll(query);
+		const e = container.querySelectorAll(query);
 
-        if (e.length > 0) {
-            iterator = new Set([...e]);
-        }
+		if (e.length > 0) {
+			iterator = new Set([...e]);
+		}
 
-        if (container.matches(query)) {
-            iterator.add(container);
-        }
+		if (container.matches(query)) {
+			iterator.add(container);
+		}
 
-        for (const [element] of iterator.entries()) {
-            if (mem.has(element)) return;
-            mem.add(element);
+		for (const [element] of iterator.entries()) {
+			if (mem.has(element)) return;
+			mem.add(element);
 
-            // this case occurs when the ATTRIBUTE_UPDATER_SELECT_THIS attribute is set
-            if (!element.hasAttribute(ATTRIBUTE_UPDATER_ATTRIBUTES)) {
-                continue;
-            }
+			// this case occurs when the ATTRIBUTE_UPDATER_SELECT_THIS attribute is set
+			if (!element.hasAttribute(ATTRIBUTE_UPDATER_ATTRIBUTES)) {
+				continue;
+			}
 
-            const attributes = element.getAttribute(ATTRIBUTE_UPDATER_ATTRIBUTES);
+			const attributes = element.getAttribute(ATTRIBUTE_UPDATER_ATTRIBUTES);
 
-            for (let [, def] of Object.entries(attributes.split(","))) {
-                def = trimSpaces(def);
-                const i = def.indexOf(" ");
-                const name = trimSpaces(def.substr(0, i));
-                const cmd = trimSpaces(def.substr(i));
+			for (let [, def] of Object.entries(attributes.split(","))) {
+				def = trimSpaces(def);
+				const i = def.indexOf(" ");
+				const name = trimSpaces(def.substr(0, i));
+				const cmd = trimSpaces(def.substr(i));
 
-                const pipe = new Pipe(cmd);
+				const pipe = new Pipe(cmd);
 
-                this[internalSymbol].callbacks.forEach((f, n) => {
-                    pipe.setCallback(n, f, element);
-                });
+				this[internalSymbol].callbacks.forEach((f, n) => {
+					pipe.setCallback(n, f, element);
+				});
 
-                let value;
-                try {
-                    element.removeAttribute(ATTRIBUTE_ERRORMESSAGE);
-                    value = pipe.run(subject);
-                } catch (e) {
-                    addErrorAttribute(element, e);
-                }
+				let value;
+				try {
+					element.removeAttribute(ATTRIBUTE_ERRORMESSAGE);
+					value = pipe.run(subject);
+				} catch (e) {
+					addErrorAttribute(element, e);
+				}
 
-                if (value === undefined) {
-                    element.removeAttribute(name);
-                } else if (element.getAttribute(name) !== value) {
-                    element.setAttribute(name, value);
-                }
+				if (value === undefined) {
+					element.removeAttribute(name);
+				} else if (element.getAttribute(name) !== value) {
+					element.setAttribute(name, value);
+				}
 
-                handleInputControlAttributeUpdate.call(this, element, name, value);
-            }
-        }
-    }
+				handleInputControlAttributeUpdate.call(this, element, name, value);
+			}
+		}
+	}
 }
 
 /**
@@ -953,52 +954,52 @@ function runUpdateAttributes(container, parts, subject) {
  */
 
 function handleInputControlAttributeUpdate(element, name, value) {
-    if (element instanceof HTMLSelectElement) {
-        switch (element.type) {
-            case "select-multiple":
-                for (const [index, opt] of Object.entries(element.options)) {
-                    opt.selected = value.indexOf(opt.value) !== -1;
-                }
-
-                break;
-            case "select-one":
-                // Only one value may be selected
-
-                for (const [index, opt] of Object.entries(element.options)) {
-                    if (opt.value === value) {
-                        element.selectedIndex = index;
-                        break;
-                    }
-                }
-
-                break;
-        }
-    } else if (element instanceof HTMLInputElement) {
-        switch (element.type) {
-            case "radio":
-                if (name === "checked") {
-                    element.checked = value !== undefined;
-                }
-                break;
-
-            case "checkbox":
-                if (name === "checked") {
-                    element.checked = value !== undefined;
-                }
-                break;
-
-            case "text":
-            default:
-                if (name === "value") {
-                    element.value = value === undefined ? "" : value;
-                }
-                break;
-        }
-    } else if (element instanceof HTMLTextAreaElement) {
-        if (name === "value") {
-            element.value = value === undefined ? "" : value;
-        }
-    }
+	if (element instanceof HTMLSelectElement) {
+		switch (element.type) {
+			case "select-multiple":
+				for (const [index, opt] of Object.entries(element.options)) {
+					opt.selected = value.indexOf(opt.value) !== -1;
+				}
+
+				break;
+			case "select-one":
+				// Only one value may be selected
+
+				for (const [index, opt] of Object.entries(element.options)) {
+					if (opt.value === value) {
+						element.selectedIndex = index;
+						break;
+					}
+				}
+
+				break;
+		}
+	} else if (element instanceof HTMLInputElement) {
+		switch (element.type) {
+			case "radio":
+				if (name === "checked") {
+					element.checked = value !== undefined;
+				}
+				break;
+
+			case "checkbox":
+				if (name === "checked") {
+					element.checked = value !== undefined;
+				}
+				break;
+
+			case "text":
+			default:
+				if (name === "value") {
+					element.value = value === undefined ? "" : value;
+				}
+				break;
+		}
+	} else if (element instanceof HTMLTextAreaElement) {
+		if (name === "value") {
+			element.value = value === undefined ? "" : value;
+		}
+	}
 }
 
 /**
@@ -1017,78 +1018,81 @@ function handleInputControlAttributeUpdate(element, name, value) {
  * @throws {TypeError} symbol must be an instance of Symbol
  */
 function addObjectWithUpdaterToElement(elements, symbol, object, config = {}) {
-    if (!(this instanceof HTMLElement)) {
-        throw new TypeError(
-            "the context of this function must be an instance of HTMLElement",
-        );
-    }
-
-    if (!(typeof symbol === "symbol")) {
-        throw new TypeError("symbol must be an instance of Symbol");
-    }
-
-    const updaters = new Set();
-
-    if (elements instanceof NodeList) {
-        elements = new Set([...elements]);
-    } else if (elements instanceof HTMLElement) {
-        elements = new Set([elements]);
-    } else if (elements instanceof Set) {
-    } else {
-        throw new TypeError(
-            `elements is not a valid type. (actual: ${typeof elements})`,
-        );
-    }
-
-    const result = [];
-
-    const updaterCallbacks = [];
-    const cb = this?.[updaterTransformerMethodsSymbol];
-    if (this instanceof HTMLElement && typeof cb === "function") {
-        const callbacks = cb.call(this);
-        if (typeof callbacks === "object") {
-            for (const [name, callback] of Object.entries(callbacks)) {
-                if (typeof callback === "function") {
-                    updaterCallbacks.push([name, callback]);
-                } else {
-                    addErrorAttribute(this, `onUpdaterPipeCallbacks: ${name} is not a function`);
-                }
-            }
-        } else {
-            addErrorAttribute(
-                this,
-                `onUpdaterPipeCallbacks do not return an object with functions`
-            );
-        }
-    }
-
-    elements.forEach((element) => {
-        if (!(element instanceof HTMLElement)) return;
-        if (element instanceof HTMLTemplateElement) return;
-
-        const u = new Updater(element, object);
-        updaters.add(u);
-
-        if (updaterCallbacks.length > 0) {
-            for (const [name, callback] of updaterCallbacks) {
-                u.setCallback(name, callback);
-            }
-        }
-
-        result.push(
-            u.run().then(() => {
-                if (config.eventProcessing === true) {
-                    u.enableEventProcessing();
-                }
-
-                return u;
-            }),
-        );
-    });
-
-    if (updaters.size > 0) {
-        addToObjectLink(this, symbol, updaters);
-    }
-
-    return result;
+	if (!(this instanceof HTMLElement)) {
+		throw new TypeError(
+			"the context of this function must be an instance of HTMLElement",
+		);
+	}
+
+	if (!(typeof symbol === "symbol")) {
+		throw new TypeError("symbol must be an instance of Symbol");
+	}
+
+	const updaters = new Set();
+
+	if (elements instanceof NodeList) {
+		elements = new Set([...elements]);
+	} else if (elements instanceof HTMLElement) {
+		elements = new Set([elements]);
+	} else if (elements instanceof Set) {
+	} else {
+		throw new TypeError(
+			`elements is not a valid type. (actual: ${typeof elements})`,
+		);
+	}
+
+	const result = [];
+
+	const updaterCallbacks = [];
+	const cb = this?.[updaterTransformerMethodsSymbol];
+	if (this instanceof HTMLElement && typeof cb === "function") {
+		const callbacks = cb.call(this);
+		if (typeof callbacks === "object") {
+			for (const [name, callback] of Object.entries(callbacks)) {
+				if (typeof callback === "function") {
+					updaterCallbacks.push([name, callback]);
+				} else {
+					addErrorAttribute(
+						this,
+						`onUpdaterPipeCallbacks: ${name} is not a function`,
+					);
+				}
+			}
+		} else {
+			addErrorAttribute(
+				this,
+				`onUpdaterPipeCallbacks do not return an object with functions`,
+			);
+		}
+	}
+
+	elements.forEach((element) => {
+		if (!(element instanceof HTMLElement)) return;
+		if (element instanceof HTMLTemplateElement) return;
+
+		const u = new Updater(element, object);
+		updaters.add(u);
+
+		if (updaterCallbacks.length > 0) {
+			for (const [name, callback] of updaterCallbacks) {
+				u.setCallback(name, callback);
+			}
+		}
+
+		result.push(
+			u.run().then(() => {
+				if (config.eventProcessing === true) {
+					u.enableEventProcessing();
+				}
+
+				return u;
+			}),
+		);
+	});
+
+	if (updaters.size > 0) {
+		addToObjectLink(this, symbol, updaters);
+	}
+
+	return result;
 }