diff --git a/packages/provider/rollup.config.js b/packages/provider/rollup.config.js
index 37765ed907261741713b723342c2f351f73c7ff3..d847e3a450584c42d9de9f9e353a76615843e338 100644
--- a/packages/provider/rollup.config.js
+++ b/packages/provider/rollup.config.js
@@ -40,7 +40,7 @@ function getBuildInfo() {
 
 export default (async () => {
     return {
-        input: (build != 'test') ? ['src/dbp-provider.js', 'src/dbp-provider-demo.js'] : glob.sync('test/**/*.js'),
+        input: (build != 'test') ? ['src/dbp-provider.js', 'src/dbp-adapter.js','src/dbp-provider-demo.js'] : glob.sync('test/**/*.js'),
         output: {
             dir: 'dist',
             entryFileNames: '[name].js',
diff --git a/packages/provider/src/adapter.js b/packages/provider/src/adapter.js
new file mode 100644
index 0000000000000000000000000000000000000000..d264ef6705c5db8934e1975921fd053fadee33e0
--- /dev/null
+++ b/packages/provider/src/adapter.js
@@ -0,0 +1,264 @@
+export class Adapter extends HTMLElement {
+    constructor() {
+        super();
+        this.connected = false;
+        this.deferSubscribe = false;
+        this.deferUnSubscribe = false;
+        // attributes (if they exist) will be updated if a property is changed by "subscribe"
+        this.reflectAttribute = true;
+
+        this.callbackStore = [];
+
+        // Previously we used direct properties like this["lang"] (instead of this.propertyStore["lang"]) for storing the
+        // properties, but the "lang" property seems to be updated before the event from the MutationObserver, so we
+        // cannot observe a value change directly (as workaround we use another property (e.g. "langValue") instead of "lang")
+        this.propertyStore = {};
+
+        // We need to store our own "last values" because we cannot be sure what the MutationObserver detects
+        this.lastProperties = {};
+
+        console.log('Adapter constructor()');
+    }
+
+    getProperty(name) {
+        return this.propertyStore[name];
+    }
+
+    getPropertyByAttributeName(name) {
+        return this[this.findPropertyName(name)];
+    }
+
+
+    setProperty(name, value) {
+        if (typeof value === 'object' && value !== null) {
+            // console.log("value is object", value);
+            this.setPropertyByAttributeName(name, value);
+        } else {
+            this.attributeChangedCallback(name, this.getPropertyByAttributeName(name), value);
+        }
+
+        this.lastProperties[name] = value;
+        this.propertyStore[name] = value;
+    }
+
+    hasPropertyChanged(name, value) {
+        return this.lastProperties[name] !== value;
+    }
+
+    hasProperty(name) {
+        // return this.hasAttribute("name")
+        return Object.hasOwnProperty.call(this.propertyStore, name);
+    }
+
+    connectedCallback() {
+
+        if (this.deferUnSubscribe) {
+            const attrs = this.unsubscribe.split(',');
+            attrs.forEach(element => this.unSubscribeProviderFor(element));
+            this.deferSubscribe = false;
+            this.unsubscribe = '';
+        }
+
+        if (this.deferSubscribe) {
+            const attrs = this.subscribe.split(',');
+            attrs.forEach(element => this.subscribeProviderFor(element));
+            this.deferSubscribe = false;
+        }
+
+        this.connected = true;
+
+        const that = this;
+
+        // Options for the observer (which mutations to observe)
+        const config = { attributes: true, childList: false, subtree: false };
+
+        // Callback function to execute when mutations are observed
+        const callback = function(mutationsList, observer) {
+            // Use traditional 'for loops' for IE 11
+            for(const mutation of mutationsList) {
+                if (mutation.type === 'attributes') {
+                    const name = mutation.attributeName;
+                    const value = that.getAttribute(name);
+
+                    if (that.hasPropertyChanged(name, value)) {
+                        console.log('AdapterProvider (' + that.tagName + ') observed attribute "' + name + '" changed');
+                        that.setProperty(name, value);
+
+                        that.callbackStore.forEach(item => {
+                            if (item.name === name) {
+                                item.callback(value);
+                            }
+                        });
+                    }
+                }
+            }
+        };
+
+        // Create an observer instance linked to the callback function
+        const observer = new MutationObserver(callback);
+
+        // Start observing the target node for configured mutations
+        observer.observe(this, config);
+
+        // get all *not observed* attributes
+        if (this.hasAttributes()) {
+            const attrs = this.attributes;
+            for(let i = attrs.length - 1; i >= 0; i--) {
+                if (['id', 'class', 'style', 'data-tag-name'].includes(attrs[i].name)) {
+                    continue;
+                }
+
+                this.setProperty(attrs[i].name, attrs[i].value);
+                console.log('AdapterProvider (' + that.tagName + ') found attribute "' + attrs[i].name + '" = "' + attrs[i].value + '"');
+            }
+        }
+    }
+
+    disconnectedCallback() {
+        const attrs = this.subscribe.split(',');
+        attrs.forEach(element => this.unSubscribeProviderFor(element));
+
+        super.disconnectedCallback();
+    }
+
+    subscribeProviderFor(element) {
+        console.log('AdapterProvider(' + this.tagName + ') subscribeProviderFor( ' + element + ' )');
+        const pair = element.trim().split(':');
+        const local = pair[0];
+        const global = pair[1] || local;
+        const that = this;
+        const event = new CustomEvent('subscribe',
+            {
+                bubbles: true,
+                composed: true,
+                detail: {
+                    name: global,
+                    callback: (value) => {
+                        console.log('AdapterProvider(' + that.tagName + ') sub/Callback ' + global + ' -> ' + local + ' = ' + value);
+                        that.setPropertiesToChildNodes(local, value);
+
+                        // If value is an object set it directly as property
+                        if (typeof value === 'object' && value !== null) {
+                            // console.log("value is object", value);
+                            that.setPropertyByAttributeName(local, value);
+                        } else {
+                            // console.log("local, that.getPropertyByAttributeName(local), value", local, that.getPropertyByAttributeName(local), value);
+                            that.attributeChangedCallback(local, that.getPropertyByAttributeName(local), value);
+
+                            // check if an attribute also exists in the tag
+                            if (that.getAttribute(local) !== null) {
+                                // we don't support attributes and provider values at the same time
+                                console.warn('Provider callback: "' + local + '" is also an attribute in tag "' + that.tagName + '", this is not supported!');
+
+                                // update attribute if reflectAttribute is enabled
+                                if (that.reflectAttribute) {
+                                    that.setAttribute(local, value);
+                                }
+                            }
+                        }
+                    },
+                    sender: this,
+                }
+            });
+        this.dispatchEvent(event);
+    }
+
+    unSubscribeProviderFor(element) {
+        console.log('AdapterProvider(' + this.tagName + ') unSubscribeProviderFor( ' + element + ' )');
+        const pair = element.trim().split(':');
+        const global = pair[1] || pair[0];
+        const event = new CustomEvent('unsubscribe',
+            {
+                bubbles: true,
+                composed: true,
+                detail: {
+                    name: global,
+                    sender: this,
+                }
+            });
+        this.dispatchEvent(event);
+    }
+
+    static get properties() {
+        return {
+            subscribe: { type: String },
+            unsubscribe: { type: String },
+        };
+    }
+
+    findPropertyName(attributeName) {
+        let resultName = attributeName;
+        const properties = this.constructor.properties;
+        // console.log("properties", properties);
+
+        for (const propertyName in properties) {
+            // console.log("findPropertyName", `${propertyName}: ${properties[propertyName]}`);
+            const attribute = properties[propertyName].attribute;
+            if (attribute === attributeName) {
+                resultName = propertyName;
+                break;
+            }
+        }
+
+        return resultName;
+    }
+
+    attributeChangedCallback(name, oldValue, newValue) {
+        switch(name) {
+            case 'subscribe':
+                console.log('AdapterProvider() attributeChangesCallback( ' + name + ', ' + oldValue + ', ' + newValue + ')');
+
+                if (this.subscribe && this.subscribe.length > 0) {
+                    if (this.connected) {
+                        const attrs = this.subscribe.split(',');
+                        attrs.forEach(element => this.unSubscribeProviderFor(element));
+                    } else {
+                        this.deferUnSubscribe = this.subscribe.length > 0;
+                        this.unsubscribe = this.subscribe;
+                    }
+                }
+
+                if (newValue !== null) {
+                    this.subscribe = newValue;
+                    if (this.connected) {
+                        const attrs = newValue.split(',');
+                        attrs.forEach(element => this.subscribeProviderFor(element));
+                    } else {
+                        this.deferSubscribe = newValue && newValue.length > 0;
+                    }
+                }
+                break;
+            default:
+                break;
+                //super.attributeChangedCallback(name, oldValue, newValue);
+        }
+
+        // console.log("this.lang", this.tagName, name, this.lang);
+        // console.log("this.entryPointUrl", this.tagName, name, this.entryPointUrl);
+        // console.trace();
+    }
+
+    /**
+     * Send a set-property event to the provider components
+     *
+     * @param name
+     * @param value
+     * @returns {boolean}
+     */
+    sendSetPropertyEvent(name, value) {
+        const event = new CustomEvent("set-property", {
+            bubbles: true,
+            composed: true,
+            detail: {'name': name, 'value': value}
+        });
+
+        return this.dispatchEvent(event);
+    }
+
+    setPropertiesToChildNodes(local, value)
+    {
+        let children = this.children;
+        Array.from(children).forEach(child => child.setAttribute(local, value));
+    }
+
+}
diff --git a/packages/provider/src/dbp-adapter.js b/packages/provider/src/dbp-adapter.js
new file mode 100644
index 0000000000000000000000000000000000000000..96f80b717f4a47bba0ab9e71c491bb5159da3a4e
--- /dev/null
+++ b/packages/provider/src/dbp-adapter.js
@@ -0,0 +1,4 @@
+import * as commonUtils from '@dbp-toolkit/common/utils';
+import {Adapter} from './adapter.js';
+
+commonUtils.defineCustomElement('dbp-provider-adapter', Adapter);
diff --git a/packages/provider/src/dbp-provider-demo.js b/packages/provider/src/dbp-provider-demo.js
index 60c7f0a7e5ec7bdfad273e1b51e34ab31c6e7626..035a992991f75b56e09526eb897743297b406c8e 100644
--- a/packages/provider/src/dbp-provider-demo.js
+++ b/packages/provider/src/dbp-provider-demo.js
@@ -5,6 +5,7 @@ import {AuthKeycloak, LoginButton} from '@dbp-toolkit/auth';
 import * as commonUtils from '@dbp-toolkit/common/utils';
 import * as commonStyles from '@dbp-toolkit/common/styles';
 import {Provider} from '@dbp-toolkit/provider';
+import {Adapter} from '@dbp-toolkit/provider';
 import {LanguageSelect} from '@dbp-toolkit/language-select';
 import DBPLitElement from "@dbp-toolkit/common/dbp-lit-element";
 
@@ -22,6 +23,7 @@ class ProviderDemo extends ScopedElementsMixin(DBPLitElement) {
             'dbp-login-button': LoginButton,
             'dbp-language-select': LanguageSelect,
             'dbp-provider': Provider,
+            'dbp-provider-adapter': Adapter,
             'dbp-consumer': DemoConsumer,
         };
     }
@@ -110,6 +112,23 @@ class ProviderDemo extends ScopedElementsMixin(DBPLitElement) {
                         </div>
                     </dbp-provider>
                 </dbp-provider>
+                
+                <h2> DBP Provider </h2>
+                <p> The dbp-provider is for third party webcomponents, which we want to configure with a provider.</p>
+                <pre>&lt;dbp-provider  id="demoadapter"  dbp-style-red="color:red;" dbp-style-green="color:green;" >&lt;/dbp-provider&gt;</pre>
+                <dbp-provider id="demoadapter"
+                              dbp-style-red="color:red;" dbp-style-green="color:green;">
+                    <pre>&lt;dbp-provider-adapter  id="a1"  subscribe="style:dbp-style-red" >&lt;/dbp-provider-adapter&gt;</pre>
+                    <dbp-provider-adapter id="a1" subscribe="style:dbp-style-red">
+                        <p> I'm a normal p tag without attributes and without style. </p>
+                        <p>  I'm a normal p tag without attributes and without style. </p>
+                        <p>  I'm a normal p tag without attributes and without style. </p>
+                    </dbp-provider-adapter>
+                    <pre>&lt;dbp-provider-adapter  id="a2"  subscribe="style:dbp-style-green" >&lt;/dbp-provider-adapter&gt;</pre>
+                    <dbp-provider-adapter id="a2" subscribe="style:dbp-style-green">
+                        <p style="background-color:green;"> I'm a normal p tag without attributes and without style. <span style="color:blue;"> I'm blue dabedidabedei...</span> </p>
+                    </dbp-provider-adapter>
+                </dbp-provider>
             </section>
         `;
     }
diff --git a/packages/provider/src/index.js b/packages/provider/src/index.js
index 34bdc9a60df3726f8fecfb1a35283fbfc2e42c6c..6f6fd2b3599dd14e85c844a5c7a4de8ac5fd3b9c 100644
--- a/packages/provider/src/index.js
+++ b/packages/provider/src/index.js
@@ -1,3 +1,5 @@
 import {Provider} from './provider.js';
+import {Adapter} from './adapter.js';
 
-export {Provider};
\ No newline at end of file
+export {Provider};
+export {Adapter};
\ No newline at end of file