diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 309eaadbf7e07c85311bb5f9d0b2014fbde2ae57..ff3298531853b964cf71c5ad3cb03f539c73691f 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -20,40 +20,40 @@ before_script:
 after_script:
   - nix develop .#gitlab --command clean-up
 
-#tests:
-#  stage: test
-#  tags:
-#    - nixos-gen3
-#  script:
-#    - nix develop .#gitlab --command run-ci-tests
-#  cache:
-#    untracked: true
-#    key:
-#      files:
-#        - pnpm-lock.yaml
-#    paths:
-#      - node_modules/
-#  rules:
-#    - if: $DEPLOY_VERSION == null
-#
-#web-tests:
-#  stage: test
-#  tags:
-#    - nixos-gen3
-#  script:
-#    -  nix develop .#gitlab --command run-ci-web-tests
-#  cache:
-#    untracked: true
-#    key:
-#      files:
-#        - pnpm-lock.yaml
-#    paths:
-#      - node_modules/
-#  artifacts:
-#    paths:
-#      - screenshot.png
-#  rules:
-#    - if: $DEPLOY_VERSION == null
+tests:
+  stage: test
+  tags:
+    - nixos-gen3
+  script:
+    - nix develop .#gitlab --command run-ci-tests
+  cache:
+    untracked: true
+    key:
+      files:
+        - pnpm-lock.yaml
+    paths:
+      - node_modules/
+  rules:
+    - if: $DEPLOY_VERSION == null
+
+web-tests:
+  stage: test
+  tags:
+    - nixos-gen3
+  script:
+    -  nix develop .#gitlab --command run-ci-web-tests
+  cache:
+    untracked: true
+    key:
+      files:
+        - pnpm-lock.yaml
+    paths:
+      - node_modules/
+  artifacts:
+    paths:
+      - screenshot.png
+  rules:
+    - if: $DEPLOY_VERSION == null
 
 release:
   stage: release
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8a9eee4b0c7b6c8e19cb34e1f0b6a5a7db8b445d..5a40741f96f79d6f4f4ef77973ff536dd9314ff1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,56 +1,14 @@
 # Changelog
 
-
-
 ## [3.65.20] - 2024-06-20
 
-### Bug Fixes
-
-- wip new pipeline
-- wip new pipeline
-
-
-
-## [3.65.19] - 2024-06-20
-
-### Bug Fixes
-
-- wip new pipeline
-
-
-
-## [3.65.18] - 2024-06-20
-
-### Bug Fixes
-
-- wip new pipeline
-
-
-
-## [3.65.17] - 2024-06-20
-
-### Bug Fixes
-
-- wip new pipeline
-
-
-
-## [3.65.16] - 2024-06-20
-
-### Bug Fixes
-
-- wip new pipeline
-
-
-
-## [3.65.15] - 2024-06-20
-
+- Changeover to new release process
 
 ## [3.65.3] - 2024-06-19
 
 ### Bug Fixes
 
-- switch nodejs_22 to nodejs_20
+- switch nodejs_22 to nodejs_20 (segmentation fault)
 
 ## [3.65.1] - 2024-06-17
 
diff --git a/development/config/import.mjs b/development/config/import.mjs
index b057d3be4f496b77e80abc03578d7574a71eaded..80aa1a3877ab0d76e51efb7c75a4644cbc0b4b2a 100644
--- a/development/config/import.mjs
+++ b/development/config/import.mjs
@@ -2,7 +2,7 @@ export const projectRoot = "/home/vs/workspaces/oss/monster/monster";
 export const sourcePath = "/home/vs/workspaces/oss/monster/monster/source";
 export const developmentPath = "/home/vs/workspaces/oss/monster/monster/development";
 export const pnpxBin = "/nix/store/77wblnm5dnmgnan3695j3mk4r7j75s5j-pnpm-8.15.5/bin/pnpx";
-export const nodeBin = "/nix/store/72m3szv59j74b12dmicmayvvlikh65qc-nodejs-22.2.0/bin/node";
+export const nodeBin = "/nix/store/6g9n96qf1yx139xklnmy3v4xhjvjgsji-nodejs-20.12.2/bin/node";
 export const license = "/**" + "\n" +
     " * Copyright © schukai GmbH and all contributing authors, {{copyRightYear}}. All rights reserved." + "\n" +
     " * Node module: @schukai/monster" + "\n" +
diff --git a/nix/scripts/deploy.nix b/nix/scripts/deploy.nix
index 11ca6bc333e13cddd8357ef89f940bb557d5f2bd..46dc69cde634505775747b5e5c65eb3151e1f374 100644
--- a/nix/scripts/deploy.nix
+++ b/nix/scripts/deploy.nix
@@ -15,8 +15,6 @@ in
     archive=$(ls ${monster} | grep tgz)
  
     echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > .npmrc
-    ${pkgs'.nodejs_20}/bin/npm publish "${monster}/$archive" 
-    
     if ! publishingResult=$(${pkgs'.nodejs_20}/bin/npm publish "${monster}/$archive" --no-git-checks --access public)
     then
       if [ -f .npmrc ] ; then rm .npmrc ; fi
diff --git a/source/components/datatable/change-button.mjs b/source/components/datatable/change-button.mjs
index f4ae679dbac44033167f805b8765efb413d39cf9..2f649b974a8b026265ff095b26ad56fed94d451b 100644
--- a/source/components/datatable/change-button.mjs
+++ b/source/components/datatable/change-button.mjs
@@ -20,6 +20,7 @@ import {
 	CustomElement,
 	registerCustomElement,
 } from "../../dom/customelement.mjs";
+import {findElementWithSelectorUpwards} from "../../dom/util.mjs";
 import { isString } from "../../types/is.mjs";
 import { State } from "../form/types/state.mjs";
 import "../form/state-button.mjs";
@@ -189,12 +190,12 @@ function initControlReferences() {
 	const selector = this.getOption("dataset.selector");
 
 	if (isString(selector)) {
-		const elements = document.querySelectorAll(selector);
-		if (elements.length !== 1) {
+
+		const element = findElementWithSelectorUpwards( this,selector);
+		if (element===null) {
 			throw new Error("the selector must match exactly one element");
 		}
 
-		const element = elements[0];
 		if (!(element instanceof HTMLElement)) {
 			throw new TypeError("the element must be a dataset");
 		}
@@ -205,12 +206,11 @@ function initControlReferences() {
 	const selector2 = this.getOption("overlay.selector");
 
 	if (isString(selector2)) {
-		const elements = document.querySelectorAll(selector2);
-		if (elements.length !== 1) {
+		const element = findElementWithSelectorUpwards( this,selector);
+		if (element===null) {
 			throw new Error("the selector must match exactly one element");
 		}
 
-		const element = elements[0];
 		if (!(element instanceof HTMLElement)) {
 			throw new TypeError("the element must be a overlay");
 		}
diff --git a/source/components/datatable/dataset.mjs b/source/components/datatable/dataset.mjs
index 7f795f771e18fd8ad7f46ec108740a029c17e4ba..2b233ce342a188067a84ed020e18d48d154151bf 100644
--- a/source/components/datatable/dataset.mjs
+++ b/source/components/datatable/dataset.mjs
@@ -12,32 +12,33 @@
  * SPDX-License-Identifier: AGPL-3.0
  */
 
-import { instanceSymbol, internalSymbol } from "../../constants.mjs";
-import { Pathfinder } from "../../data/pathfinder.mjs";
-import { getLinkedObjects, hasObjectLink } from "../../dom/attributes.mjs";
-import { customElementUpdaterLinkSymbol } from "../../dom/constants.mjs";
+import {instanceSymbol, internalSymbol} from "../../constants.mjs";
+import {Pathfinder} from "../../data/pathfinder.mjs";
+import {getLinkedObjects, hasObjectLink} from "../../dom/attributes.mjs";
+import {customElementUpdaterLinkSymbol} from "../../dom/constants.mjs";
 import {
-	assembleMethodSymbol,
-	CustomElement,
-	attributeObserverSymbol,
-	registerCustomElement,
+    assembleMethodSymbol,
+    CustomElement,
+    attributeObserverSymbol,
+    registerCustomElement,
 } from "../../dom/customelement.mjs";
-import { isString } from "../../types/is.mjs";
-import { Observer } from "../../types/observer.mjs";
-import { clone } from "../../util/clone.mjs";
+import {findElementWithSelectorUpwards} from "../../dom/util.mjs";
+import {isString} from "../../types/is.mjs";
+import {Observer} from "../../types/observer.mjs";
+import {clone} from "../../util/clone.mjs";
 import {
-	ATTRIBUTE_DATASOURCE_SELECTOR,
-	ATTRIBUTE_DATATABLE_INDEX,
+    ATTRIBUTE_DATASOURCE_SELECTOR,
+    ATTRIBUTE_DATATABLE_INDEX,
 } from "./constants.mjs";
-import { Datasource } from "./datasource.mjs";
-import { DatasetStyleSheet } from "./stylesheet/dataset.mjs";
+import {Datasource} from "./datasource.mjs";
+import {DatasetStyleSheet} from "./stylesheet/dataset.mjs";
 import {
-	handleDataSourceChanges,
-	datasourceLinkedElementSymbol,
+    handleDataSourceChanges,
+    datasourceLinkedElementSymbol,
 } from "./util.mjs";
-import { FormStyleSheet } from "../stylesheet/form.mjs";
+import {FormStyleSheet} from "../stylesheet/form.mjs";
 
-export { DataSet };
+export {DataSet};
 
 /**
  * The data set component is used to show the data of a data source.
@@ -78,185 +79,184 @@ export { DataSet };
  * @summary A data set
  */
 class DataSet extends CustomElement {
-	/**
-	 * This method is called by the `instanceof` operator.
-	 * @returns {symbol}
-	 */
-	static get [instanceSymbol]() {
-		return Symbol.for("@schukai/monster/components/dataset@@instance");
-	}
-
-	/**
-	 * This method determines which attributes are to be monitored by `attributeChangedCallback()`.
-	 *
-	 * @return {string[]}
-	 * @since 1.15.0
-	 */
-	static get observedAttributes() {
-		const attributes = super.observedAttributes;
-		attributes.push(ATTRIBUTE_DATATABLE_INDEX);
-		return attributes;
-	}
-
-	/**
-	 * To set the options via the html tag the attribute `data-monster-options` must be used.
-	 * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
-	 *
-	 * The individual configuration values can be found in the table.
-	 *
-	 * @property {Object} templates Template definitions
-	 * @property {string} templates.main Main template
-	 * @property {object} datasource The datasource
-	 * @property {string} datasource.selector The selector of the datasource
-	 * @property {object} mapping The mapping
-	 * @property {string} mapping.data The data
-	 * @property {number} mapping.index The index
-	 * @property {Array} data The data
-	 */
-	get defaults() {
-		const obj = Object.assign({}, super.defaults, {
-			templates: {
-				main: getTemplate(),
-			},
-
-			datasource: {
-				selector: null,
-			},
-
-			mapping: {
-				data: "dataset",
-				index: 0,
-			},
-
-			data: {},
-		});
-
-		updateOptionsFromArguments.call(this, obj);
-		return obj;
-	}
-
-	/**
-	 *
-	 * @return {string}
-	 */
-	static getTag() {
-		return "monster-dataset";
-	}
-
-	write() {
-		return new Promise((resolve, reject) => {
-			if (!this[datasourceLinkedElementSymbol]) {
-				reject(new Error("No datasource"));
-				return;
-			}
-
-			const internalUpdateCloneData = this.getInternalUpdateCloneData();
-			if (!internalUpdateCloneData) {
-				reject(new Error("No update data"));
-				return;
-			}
-
-			const internalData = internalUpdateCloneData?.["data"];
-			if (
-				internalData === undefined ||
-				internalData === null ||
-				internalData === ""
-			) {
-				reject(new Error("No data"));
-				return;
-			}
-
-			setTimeout(() => {
-				const path = this.getOption("mapping.data");
-				const index = this.getOption("mapping.index");
-
-				let pathWithIndex;
-
-				if (isString(path) && path !== "") {
-					pathWithIndex = path + "." + index;
-				} else {
-					pathWithIndex = index;
-				}
-
-				const data = this[datasourceLinkedElementSymbol].data;
-				const unref = JSON.stringify(data);
-				const ref = JSON.parse(unref);
-
-				new Pathfinder(ref).setVia(pathWithIndex, internalData);
-
-				this[datasourceLinkedElementSymbol].data = ref;
-
-				resolve();
-			}, 0);
-		});
-	}
-
-	/**
-	 * This method is responsible for assembling the component.
-	 *
-	 * It calls the parent's assemble method first, then initializes control references and event handlers.
-	 * If the `datasource.selector` option is provided and is a string, it searches for the corresponding
-	 * element in the DOM using that selector.
-	 *
-	 * If the selector matches exactly one element, it checks if the element is an instance of the `Datasource` class.
-	 *
-	 * If it is, the component's `datasourceLinkedElementSymbol` property is set to the element, and the component
-	 * attaches an observer to the datasource's changes.
-	 *
-	 * The observer is a function that calls the `handleDataSourceChanges` method in the context of the component.
-	 * Additionally, the component attaches an observer to itself, which also calls the `handleDataSourceChanges`
-	 * method in the component's context.
-	 */
-	[assembleMethodSymbol]() {
-		super[assembleMethodSymbol]();
-
-		// initControlReferences.call(self);
-		initEventHandler.call(this);
-
-		const selector = this.getOption("datasource.selector");
-
-		if (isString(selector)) {
-			const elements = document.querySelectorAll(selector);
-			if (elements.length !== 1) {
-				throw new Error("the selector must match exactly one element");
-			}
-
-			const element = elements[0];
-			if (!(element instanceof Datasource)) {
-				throw new TypeError("the element must be a datasource");
-			}
-
-			this[datasourceLinkedElementSymbol] = element;
-			element.datasource.attachObserver(
-				new Observer(handleDataSourceChanges.bind(this)),
-			);
-		}
-
-		this.attachObserver(
-			new Observer(() => {
-				handleDataSourceChanges.call(this);
-			}),
-		);
-	}
-
-	/**
-	 * @return [CSSStyleSheet]
-	 */
-	static getCSSStyleSheet() {
-		return [FormStyleSheet, DatasetStyleSheet];
-	}
+    /**
+     * This method is called by the `instanceof` operator.
+     * @returns {symbol}
+     */
+    static get [instanceSymbol]() {
+        return Symbol.for("@schukai/monster/components/dataset@@instance");
+    }
+
+    /**
+     * This method determines which attributes are to be monitored by `attributeChangedCallback()`.
+     *
+     * @return {string[]}
+     * @since 1.15.0
+     */
+    static get observedAttributes() {
+        const attributes = super.observedAttributes;
+        attributes.push(ATTRIBUTE_DATATABLE_INDEX);
+        return attributes;
+    }
+
+    /**
+     * To set the options via the html tag the attribute `data-monster-options` must be used.
+     * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
+     *
+     * The individual configuration values can be found in the table.
+     *
+     * @property {Object} templates Template definitions
+     * @property {string} templates.main Main template
+     * @property {object} datasource The datasource
+     * @property {string} datasource.selector The selector of the datasource
+     * @property {object} mapping The mapping
+     * @property {string} mapping.data The data
+     * @property {number} mapping.index The index
+     * @property {Array} data The data
+     */
+    get defaults() {
+        const obj = Object.assign({}, super.defaults, {
+            templates: {
+                main: getTemplate(),
+            },
+
+            datasource: {
+                selector: null,
+            },
+
+            mapping: {
+                data: "dataset",
+                index: 0,
+            },
+
+            data: {},
+        });
+
+        updateOptionsFromArguments.call(this, obj);
+        return obj;
+    }
+
+    /**
+     *
+     * @return {string}
+     */
+    static getTag() {
+        return "monster-dataset";
+    }
+
+    write() {
+        return new Promise((resolve, reject) => {
+            if (!this[datasourceLinkedElementSymbol]) {
+                reject(new Error("No datasource"));
+                return;
+            }
+
+            const internalUpdateCloneData = this.getInternalUpdateCloneData();
+            if (!internalUpdateCloneData) {
+                reject(new Error("No update data"));
+                return;
+            }
+
+            const internalData = internalUpdateCloneData?.["data"];
+            if (
+                internalData === undefined ||
+                internalData === null ||
+                internalData === ""
+            ) {
+                reject(new Error("No data"));
+                return;
+            }
+
+            setTimeout(() => {
+                const path = this.getOption("mapping.data");
+                const index = this.getOption("mapping.index");
+
+                let pathWithIndex;
+
+                if (isString(path) && path !== "") {
+                    pathWithIndex = path + "." + index;
+                } else {
+                    pathWithIndex = index;
+                }
+
+                const data = this[datasourceLinkedElementSymbol].data;
+                const unref = JSON.stringify(data);
+                const ref = JSON.parse(unref);
+
+                new Pathfinder(ref).setVia(pathWithIndex, internalData);
+
+                this[datasourceLinkedElementSymbol].data = ref;
+
+                resolve();
+            }, 0);
+        });
+    }
+
+    /**
+     * This method is responsible for assembling the component.
+     *
+     * It calls the parent's assemble method first, then initializes control references and event handlers.
+     * If the `datasource.selector` option is provided and is a string, it searches for the corresponding
+     * element in the DOM using that selector.
+     *
+     * If the selector matches exactly one element, it checks if the element is an instance of the `Datasource` class.
+     *
+     * If it is, the component's `datasourceLinkedElementSymbol` property is set to the element, and the component
+     * attaches an observer to the datasource's changes.
+     *
+     * The observer is a function that calls the `handleDataSourceChanges` method in the context of the component.
+     * Additionally, the component attaches an observer to itself, which also calls the `handleDataSourceChanges`
+     * method in the component's context.
+     */
+    [assembleMethodSymbol]() {
+        super[assembleMethodSymbol]();
+
+        // initControlReferences.call(self);
+        initEventHandler.call(this);
+
+        const selector = this.getOption("datasource.selector");
+
+        if (isString(selector)) {
+            const element = findElementWithSelectorUpwards(this, selector);
+            if (element === null) {
+                throw new Error("the selector must match exactly one element");
+            }
+
+            if (!(element instanceof Datasource)) {
+                throw new TypeError("the element must be a datasource");
+            }
+
+            this[datasourceLinkedElementSymbol] = element;
+            element.datasource.attachObserver(
+                new Observer(handleDataSourceChanges.bind(this)),
+            );
+        }
+
+        this.attachObserver(
+            new Observer(() => {
+                handleDataSourceChanges.call(this);
+            }),
+        );
+    }
+
+    /**
+     * @return [CSSStyleSheet]
+     */
+    static getCSSStyleSheet() {
+        return [FormStyleSheet, DatasetStyleSheet];
+    }
 }
 
 /**
  * @private
  */
 function initEventHandler() {
-	this[attributeObserverSymbol][ATTRIBUTE_DATATABLE_INDEX] = () => {
-		const index = this.getAttribute(ATTRIBUTE_DATATABLE_INDEX);
-		if (index) {
-			this.setOption("mapping.index", parseInt(index, 10));
-		}
-	};
+    this[attributeObserverSymbol][ATTRIBUTE_DATATABLE_INDEX] = () => {
+        const index = this.getAttribute(ATTRIBUTE_DATATABLE_INDEX);
+        if (index) {
+            this.setOption("mapping.index", parseInt(index, 10));
+        }
+    };
 }
 
 /**
@@ -264,17 +264,17 @@ function initEventHandler() {
  * @param {Object} options
  */
 function updateOptionsFromArguments(options) {
-	const index = this.getAttribute(ATTRIBUTE_DATATABLE_INDEX);
+    const index = this.getAttribute(ATTRIBUTE_DATATABLE_INDEX);
 
-	if (index !== null && index !== undefined) {
-		options.mapping.index = parseInt(index, 10);
-	}
+    if (index !== null && index !== undefined) {
+        options.mapping.index = parseInt(index, 10);
+    }
 
-	const selector = this.getAttribute(ATTRIBUTE_DATASOURCE_SELECTOR);
+    const selector = this.getAttribute(ATTRIBUTE_DATASOURCE_SELECTOR);
 
-	if (selector) {
-		options.datasource.selector = selector;
-	}
+    if (selector) {
+        options.datasource.selector = selector;
+    }
 }
 
 /**
@@ -282,8 +282,8 @@ function updateOptionsFromArguments(options) {
  * @return {string}
  */
 function getTemplate() {
-	// language=HTML
-	return `
+    // language=HTML
+    return `
         <div data-monster-role="control" part="control">
             <slot></slot>
         </div>
diff --git a/source/components/datatable/datatable.mjs b/source/components/datatable/datatable.mjs
index cb418a1a2526f561402f24f115c39275ec38e678..cb43ce25a3b1512065a1f5fe5390d4d8c0045d7c 100644
--- a/source/components/datatable/datatable.mjs
+++ b/source/components/datatable/datatable.mjs
@@ -511,8 +511,7 @@ function getFilterConfigKey() {
  * @returns {Promise}
  */
 function getHostConfig(callback) {
-	const document = getDocument();
-	const host = document.querySelector("monster-host");
+	const host = findElementWithSelectorUpwards( this,"monster-host");
 
 	if (!(host && this.id)) {
 		return Promise.resolve({});
@@ -608,8 +607,7 @@ function updateConfigColumnBar() {
 		map[option.name] = option.visible;
 	}
 
-	const document = getDocument();
-	const host = document.querySelector("monster-host");
+	const host = findElementWithSelectorUpwards( this,"monster-host");
 	if (!(host && this.id)) {
 		return;
 	}
@@ -816,8 +814,7 @@ function storeOrderStatement(doFetch) {
 	const statement = createOrderStatement(headers);
 	setDataSource.call(this, { orderBy: statement }, doFetch);
 
-	const document = getDocument();
-	const host = document.querySelector("monster-host");
+	const host = findElementWithSelectorUpwards( this,"monster-host");
 	if (!(host && this.id)) {
 		return;
 	}
diff --git a/source/components/datatable/filter.mjs b/source/components/datatable/filter.mjs
index 4e2c4014a8d3e257c4fde6423051494290a32ef2..ed45310594a76230d87777d08a6b9cdc3e97509b 100644
--- a/source/components/datatable/filter.mjs
+++ b/source/components/datatable/filter.mjs
@@ -726,8 +726,7 @@ function initTabEvents() {
 				}
 			}
 
-			const document = getDocument();
-			const host = document.querySelector("monster-host");
+			const host = findElementWithSelectorUpwards( this,"monster-host");
 			if (!(host && this.id)) {
 				return;
 			}
@@ -768,8 +767,7 @@ function updateFilterTabs() {
 		return;
 	}
 
-	const document = getDocument();
-	const host = document.querySelector("monster-host");
+	const host = findElementWithSelectorUpwards( this,"monster-host");
 	if (!(host && this.id)) {
 		return;
 	}
@@ -1067,8 +1065,7 @@ function getControlValuesFromLabel(label) {
  * @returns {Promise<unknown>}
  */
 function initFromConfig() {
-	const document = getDocument();
-	const host = document.querySelector("monster-host");
+	const host = findElementWithSelectorUpwards( this,"monster-host");
 
 	if (!(isInstance(host, Host) && this.id)) {
 		return Promise.resolve();
@@ -1111,8 +1108,7 @@ function initFromConfig() {
  * @private
  */
 function updateConfig() {
-	const document = getDocument();
-	const host = document.querySelector("monster-host");
+	const host = findElementWithSelectorUpwards( this,"monster-host");
 	if (!(host && this.id)) {
 		return;
 	}
diff --git a/source/components/datatable/pagination.mjs b/source/components/datatable/pagination.mjs
index 5ff4a9c4cd117fd09a63cca4d02b72aed7b5882a..93ce8c562cd18db9d82347a7df2691d0eca4e939 100644
--- a/source/components/datatable/pagination.mjs
+++ b/source/components/datatable/pagination.mjs
@@ -17,6 +17,7 @@ import {
 	CustomElement,
 	registerCustomElement,
 } from "../../dom/customelement.mjs";
+import {findElementWithSelectorUpwards} from "../../dom/util.mjs";
 import { ThemeStyleSheet } from "../stylesheet/theme.mjs";
 import { ATTRIBUTE_DATASOURCE_SELECTOR } from "./constants.mjs";
 import { Datasource } from "./datasource.mjs";
@@ -188,12 +189,11 @@ class Pagination extends CustomElement {
 		const selector = this.getOption("datasource.selector", "");
 
 		if (isString(selector)) {
-			const elements = document.querySelectorAll(selector);
-			if (elements.length !== 1) {
+			const element = findElementWithSelectorUpwards( this,selector);
+			if (element===null) {
 				throw new Error("the selector must match exactly one element");
 			}
-
-			const element = elements[0];
+			
 			if (!(element instanceof Datasource)) {
 				throw new TypeError("the element must be a datasource");
 			}
diff --git a/source/components/datatable/save-button.mjs b/source/components/datatable/save-button.mjs
index 97652648d57fc6f09ad1985cf7b487913cfc25cc..9e3322e1eddc84508dc7e3421c2cb69dfdeff7f1 100644
--- a/source/components/datatable/save-button.mjs
+++ b/source/components/datatable/save-button.mjs
@@ -22,6 +22,7 @@ import {
 	attributeObserverSymbol,
 	registerCustomElement,
 } from "../../dom/customelement.mjs";
+import {findElementWithSelectorUpwards} from "../../dom/util.mjs";
 import { isString, isArray } from "../../types/is.mjs";
 import { Observer } from "../../types/observer.mjs";
 import { TokenList } from "../../types/tokenlist.mjs";
@@ -154,12 +155,12 @@ class SaveButton extends CustomElement {
 		const selector = this.getOption("datasource.selector");
 
 		if (isString(selector)) {
-			const elements = document.querySelectorAll(selector);
-			if (elements.length !== 1) {
+
+			const element = findElementWithSelectorUpwards( this,selector);
+			if (element===null) {
 				throw new Error("the selector must match exactly one element");
 			}
-
-			const element = elements[0];
+			
 			if (!(element instanceof Datasource)) {
 				throw new TypeError("the element must be a datasource");
 			}
diff --git a/source/components/datatable/status.mjs b/source/components/datatable/status.mjs
index 6feec9b8309a00583bcbec5532ea39a077d43518..79f617b1142782b511d66378dc3c32cb3cce8e9e 100644
--- a/source/components/datatable/status.mjs
+++ b/source/components/datatable/status.mjs
@@ -17,6 +17,7 @@ import {
 	CustomElement,
 	registerCustomElement,
 } from "../../dom/customelement.mjs";
+import {findElementWithSelectorUpwards} from "../../dom/util.mjs";
 import { ThemeStyleSheet } from "../stylesheet/theme.mjs";
 import { Datasource } from "./datasource.mjs";
 import { SpinnerStyleSheet } from "../stylesheet/spinner.mjs";
@@ -174,12 +175,12 @@ function initEventHandler() {
 	const self = this;
 
 	if (isString(selector)) {
-		const elements = document.querySelectorAll(selector);
-		if (elements.length !== 1) {
+
+		const element = findElementWithSelectorUpwards( this,selector);
+		if (element===null) {
 			throw new Error("the selector must match exactly one element");
 		}
-
-		const element = elements[0];
+		
 		if (!(element instanceof Datasource)) {
 			throw new TypeError("the element must be a datasource");
 		}
diff --git a/source/data/datasource/dom.mjs b/source/data/datasource/dom.mjs
index 28c5612a80a7519357ee35bf32eb04c878ff5205..bf7d4a607f513fec276dbae971b26daf4da13b64 100644
--- a/source/data/datasource/dom.mjs
+++ b/source/data/datasource/dom.mjs
@@ -12,11 +12,12 @@
  * SPDX-License-Identifier: AGPL-3.0
  */
 
-import { instanceSymbol } from "../../constants.mjs";
-import { isObject } from "../../types/is.mjs";
-import { Datasource } from "../datasource.mjs";
+import {instanceSymbol} from "../../constants.mjs";
+import {findElementWithSelectorUpwards} from "../../dom/util.mjs";
+import {isObject} from "../../types/is.mjs";
+import {Datasource} from "../datasource.mjs";
 
-export { DomStorage };
+export {DomStorage};
 
 /**
  * The DomStorage is a class that stores data in memory.
@@ -26,93 +27,93 @@ export { DomStorage };
  * @memberOf Monster.Data.Datasource
  */
 class DomStorage extends Datasource {
-	/**
-	 * @param {Object} [options] options contains definitions for the datasource.
-	 */
-	constructor(options) {
-		super();
+    /**
+     * @param {Object} [options] options contains definitions for the datasource.
+     */
+    constructor(options) {
+        super();
 
-		if (isObject(options)) {
-			this.setOptions(options);
-		}
-	}
+        if (isObject(options)) {
+            this.setOptions(options);
+        }
+    }
 
-	/**
-	 * This method is called by the `instanceof` operator.
-	 * @returns {symbol}
-	 */
-	static get [instanceSymbol]() {
-		return Symbol.for("@schukai/monster/data/datasource/storage/dom-storage");
-	}
+    /**
+     * This method is called by the `instanceof` operator.
+     * @returns {symbol}
+     */
+    static get [instanceSymbol]() {
+        return Symbol.for("@schukai/monster/data/datasource/storage/dom-storage");
+    }
 
-	/**
-	 * @property {Object} defaults
-	 * @property {Object} defaults.read
-	 * @property {string} defaults.read.selector
-	 * @property {Object} defaults.write
-	 * @property {string} defaults.write.selector
-	 */
-	get defaults() {
-		return Object.assign({}, super.defaults, {
-			read: {
-				selector: undefined,
-			},
-			write: {
-				selector: undefined,
-			},
-		});
-	}
+    /**
+     * @property {Object} defaults
+     * @property {Object} defaults.read
+     * @property {string} defaults.read.selector
+     * @property {Object} defaults.write
+     * @property {string} defaults.write.selector
+     */
+    get defaults() {
+        return Object.assign({}, super.defaults, {
+            read: {
+                selector: undefined,
+            },
+            write: {
+                selector: undefined,
+            },
+        });
+    }
 
-	/**
-	 * @return {Promise}
-	 * @throws {Error} The read selector is not defined
-	 * @throws {Error} There are no storage element
-	 */
-	read() {
-		const selector = this.getOption("read.selector", undefined);
-		if (!selector) {
-			throw new Error("The read selector is not defined");
-		}
+    /**
+     * @return {Promise}
+     * @throws {Error} The read selector is not defined
+     * @throws {Error} There are no storage element
+     */
+    read() {
+        const selector = this.getOption("read.selector", undefined);
+        if (!selector) {
+            throw new Error("The read selector is not defined");
+        }
 
-		const storage = document.querySelector(selector);
-		if (!storage) {
-			throw new Error("There are no storage element");
-		}
+        const storage = findElementWithSelectorUpwards(this, selector);
+        if (!storage) {
+            throw new Error("There is no storage element");
+        }
 
-		return new Promise((resolve, reject) => {
-			try {
-				const data = JSON.parse(storage.innerHTML);
-				this.set(data);
-				resolve(data);
-			} catch (e) {
-				reject(e);
-			}
-		});
-	}
+        return new Promise((resolve, reject) => {
+            try {
+                const data = JSON.parse(storage.innerHTML);
+                this.set(data);
+                resolve(data);
+            } catch (e) {
+                reject(e);
+            }
+        });
+    }
 
-	/**
-	 * @return {Promise}
-	 * @throws {Error} The write selector is not defined
-	 * @throws {Error} There are no storage element
-	 */
-	write() {
-		const selector = this.getOption("write.selector");
-		if (!selector) {
-			throw new Error("The write selector is not defined");
-		}
+    /**
+     * @return {Promise}
+     * @throws {Error} The write selector is not defined
+     * @throws {Error} There are no storage element
+     */
+    write() {
+        const selector = this.getOption("write.selector");
+        if (!selector) {
+            throw new Error("The option write.selector is not defined");
+        }
 
-		const storage = document.querySelector(selector);
-		if (!storage) {
-			throw new Error("There are no storage element");
-		}
+        const storage = findElementWithSelectorUpwards(this, selector);
+        if (!storage) {
+            throw new Error("There is no storage element");
+        }
 
-		return new Promise((resolve, reject) => {
-			try {
-				storage.innerHTML = JSON.stringify(this.get());
-				resolve(storage);
-			} catch (e) {
-				reject(e);
-			}
-		});
-	}
+        return new Promise((resolve, reject) => {
+            try {
+                storage.innerHTML = JSON.stringify(this.get());
+                resolve(storage);
+            } catch (e) {
+                reject(e);
+            }
+        });
+    }
 }
diff --git a/source/dom/resource.mjs b/source/dom/resource.mjs
index 86bb08823a59036a626d2b648611f7cb1d38e86e..ea78064ab7868430bb7551a5cf86be1e1377d008 100644
--- a/source/dom/resource.mjs
+++ b/source/dom/resource.mjs
@@ -242,7 +242,6 @@ function addEvents() {
 		this[referenceSymbol].removeEventListener("error", onError);
 		this[referenceSymbol].removeEventListener("load", onLoad);
 		this[internalStateSymbol].getSubject()["loaded"] = true;
-		return;
 	};
 
 	this[referenceSymbol].addEventListener("load", onLoad, false);
diff --git a/source/dom/resource/data.mjs b/source/dom/resource/data.mjs
index 7adcbaf1591d483d911e0e6384c38ec14682b198..0eaff437aba2dcdd60830f5ad864d54cf1c448d5 100644
--- a/source/dom/resource/data.mjs
+++ b/source/dom/resource/data.mjs
@@ -12,26 +12,28 @@
  * SPDX-License-Identifier: AGPL-3.0
  */
 
-import { internalStateSymbol } from "../../constants.mjs";
-import { extend } from "../../data/extend.mjs";
-import { getGlobalFunction } from "../../types/global.mjs";
+import {internalStateSymbol} from "../../constants.mjs";
+import {extend} from "../../data/extend.mjs";
+import {getGlobalFunction} from "../../types/global.mjs";
+import {addAttributeToken} from "../attributes.mjs";
 import {
-	ATTRIBUTE_CLASS,
-	ATTRIBUTE_ERRORMESSAGE,
-	ATTRIBUTE_ID,
-	ATTRIBUTE_SRC,
-	ATTRIBUTE_TITLE,
-	ATTRIBUTE_TYPE,
-	TAG_SCRIPT,
+    ATTRIBUTE_CLASS,
+    ATTRIBUTE_ERRORMESSAGE,
+    ATTRIBUTE_ID,
+    ATTRIBUTE_SRC,
+    ATTRIBUTE_TITLE,
+    ATTRIBUTE_TYPE,
+    TAG_SCRIPT,
 } from "../constants.mjs";
 import {
-	KEY_DOCUMENT,
-	KEY_QUERY,
-	referenceSymbol,
-	Resource,
+    KEY_DOCUMENT,
+    KEY_QUERY,
+    referenceSymbol,
+    Resource,
 } from "../resource.mjs";
-import { instanceSymbol } from "../../constants.mjs";
-export { Data };
+import {instanceSymbol} from "../../constants.mjs";
+
+export {Data};
 
 /**
  * This class is used by the resource manager to embed data.
@@ -43,58 +45,59 @@ export { Data };
  * @summary A Data Resource class
  */
 class Data extends Resource {
-	/**
-	 * @property {string} mode=cors https://developer.mozilla.org/en-US/docs/Web/API/fetch
-	 * @property {string} credentials=same-origin https://developer.mozilla.org/en-US/docs/Web/API/fetch
-	 * @property {string} type=application/json {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-type}
-	 */
-	get defaults() {
-		return extend({}, super.defaults, {
-			mode: "cors",
-			credentials: "same-origin",
-			type: "application/json",
-		});
-	}
-
-	/**
-	 *
-	 * @return {Monster.DOM.Resource.Data}
-	 */
-	create() {
-		createElement.call(this);
-		return this;
-	}
-
-	/**
-	 * This method appends the HTMLElement to the specified document
-	 *
-	 * throws {Error} target not found
-	 * @return {Monster.DOM.Resource}
-	 */
-	connect() {
-		if (!(this[referenceSymbol] instanceof HTMLElement)) {
-			this.create();
-		}
-
-		appendToDocument.call(this);
-		return this;
-	}
-
-	/**
-	 * This method is called by the `instanceof` operator.
-	 * @returns {symbol}
-	 * @since 2.1.0
-	 */
-	static get [instanceSymbol]() {
-		return Symbol.for("@schukai/monster/dom/resource/data");
-	}
-
-	/**
-	 * @return {string}
-	 */
-	static getURLAttribute() {
-		return ATTRIBUTE_SRC;
-	}
+    /**
+     * @property {string} mode=cors https://developer.mozilla.org/en-US/docs/Web/API/fetch
+     * @property {string} credentials=same-origin https://developer.mozilla.org/en-US/docs/Web/API/fetch
+     * @property {string} type=application/json {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-type}
+     */
+    get defaults() {
+        return extend({}, super.defaults, {
+            mode: "cors",
+            credentials: "same-origin",
+            type: "application/json",
+        });
+    }
+
+    /**
+     *
+     * @return {Monster.DOM.Resource.Data}
+     */
+    create() {
+        createElement.call(this);
+        return this;
+    }
+
+    /**
+     * This method appends the HTMLElement to the specified document
+     *
+     * throws {Error} target not found
+     * @return {Monster.DOM.Resource}
+     */
+    connect() {
+        const self = this;
+        if (!(this[referenceSymbol] instanceof HTMLElement)) {
+            this.create();
+        }
+
+        appendToDocument.call(this);
+        return this;
+    }
+
+    /**
+     * This method is called by the `instanceof` operator.
+     * @returns {symbol}
+     * @since 2.1.0
+     */
+    static get [instanceSymbol]() {
+        return Symbol.for("@schukai/monster/dom/resource/data");
+    }
+
+    /**
+     * @return {string}
+     */
+    static getURLAttribute() {
+        return ATTRIBUTE_SRC;
+    }
 }
 
 /**
@@ -102,21 +105,21 @@ class Data extends Resource {
  * @return {Monster.DOM.Resource.Data}
  */
 function createElement() {
-	const document = this.getOption(KEY_DOCUMENT);
-	this[referenceSymbol] = document.createElement(TAG_SCRIPT);
-
-	for (const key of [
-		ATTRIBUTE_TYPE,
-		ATTRIBUTE_ID,
-		ATTRIBUTE_CLASS,
-		ATTRIBUTE_TITLE,
-	]) {
-		if (this.getOption(key) !== undefined) {
-			this[referenceSymbol][key] = this.getOption(key);
-		}
-	}
-
-	return this;
+    const document = this.getOption(KEY_DOCUMENT);
+    this[referenceSymbol] = document.createElement(TAG_SCRIPT);
+
+    for (const key of [
+        ATTRIBUTE_TYPE,
+        ATTRIBUTE_ID,
+        ATTRIBUTE_CLASS,
+        ATTRIBUTE_TITLE,
+    ]) {
+        if (this.getOption(key) !== undefined) {
+            this[referenceSymbol][key] = this.getOption(key);
+        }
+    }
+
+    return this;
 }
 
 /**
@@ -125,41 +128,41 @@ function createElement() {
  * throws {Error} target not found
  */
 function appendToDocument() {
-	const targetNode = document.querySelector(this.getOption(KEY_QUERY, "head"));
-	if (!(targetNode instanceof HTMLElement)) {
-		throw new Error("target not found");
-	}
-
-	targetNode.appendChild(this[referenceSymbol]);
-
-	getGlobalFunction("fetch")(this.getOption(ATTRIBUTE_SRC), {
-		method: "GET", // *GET, POST, PUT, DELETE, etc.
-		mode: this.getOption("mode", "cors"), // no-cors, *cors, same-origin
-		cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
-		credentials: this.getOption("credentials", "same-origin"), // include, *same-origin, omit
-		headers: {
-			Accept: this.getOption("type", "application/json"),
-		},
-		redirect: "follow", // manual, *follow, error
-		referrerPolicy: "no-referrer", // no-referrer,
-	})
-		.then((response) => {
-			return response.text();
-		})
-		.then((text) => {
-			const textNode = document.createTextNode(text);
-			this[referenceSymbol].appendChild(textNode);
-
-			this[internalStateSymbol].getSubject()["loaded"] = true;
-		})
-		.catch((e) => {
-			this[internalStateSymbol].setSubject({
-				loaded: true,
-				error: e.toString(),
-			});
-
-			targetNode.setAttribute(ATTRIBUTE_ERRORMESSAGE, e.toString());
-		});
-
-	return this;
+    const targetNode = document.querySelector(this.getOption(KEY_QUERY, "head"));
+    if (!(targetNode instanceof HTMLElement)) {
+        throw new Error("target not found");
+    }
+
+    targetNode.appendChild(this[referenceSymbol]);
+
+    getGlobalFunction("fetch")(this.getOption(ATTRIBUTE_SRC), {
+        method: "GET", // *GET, POST, PUT, DELETE, etc.
+        mode: this.getOption("mode", "cors"), // no-cors, *cors, same-origin
+        cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
+        credentials: this.getOption("credentials", "same-origin"), // include, *same-origin, omit
+        headers: {
+            Accept: this.getOption("type", "application/json"),
+        },
+        redirect: "follow", // manual, *follow, error
+        referrerPolicy: "no-referrer", // no-referrer,
+    })
+        .then((response) => {
+            return response.text();
+        })
+        .then((text) => {
+            const textNode = document.createTextNode(text);
+            this[referenceSymbol].appendChild(textNode);
+
+            this[internalStateSymbol].getSubject()["loaded"] = true;
+        })
+        .catch((e) => {
+            this[internalStateSymbol].setSubject({
+                loaded: true,
+                error: e.toString(),
+            });
+
+            targetNode.setAttribute(ATTRIBUTE_ERRORMESSAGE, e.toString());
+        });
+
+    return this;
 }