diff --git a/packages/common/index.js b/packages/common/index.js
index c4e7bb0281a57e27aaef99755e17e35cb21d0b76..ed77d0e4648632f28ec8ad79ce15b2fb24051847 100644
--- a/packages/common/index.js
+++ b/packages/common/index.js
@@ -2,11 +2,11 @@ import {EventBus} from './src/eventbus.js';
 import {createLinkedAbortController, createTimeoutAbortSignal} from './src/abort.js';
 import {getIconSVGURL, getIconCSS, Icon} from './src/icon.js';
 import {MiniSpinner} from './src/mini-spinner.js';
-import {Button} from './src/button.js';
+import {Button, LoadingButton} from './src/button.js';
 import {Spinner} from './src/spinner.js';
 
 export {EventBus, createLinkedAbortController, createTimeoutAbortSignal};
 export {getIconSVGURL, getIconCSS, Icon};
 export {MiniSpinner};
-export {Button};
+export {Button, LoadingButton};
 export {Spinner};
\ No newline at end of file
diff --git a/packages/common/src/button.js b/packages/common/src/button.js
index 26d192a959cc784475ff1964ad002d1fe0a4c9d2..26d22b7b361a24f0ad5b7800bf464dd8ad2761d3 100644
--- a/packages/common/src/button.js
+++ b/packages/common/src/button.js
@@ -80,3 +80,79 @@ export class Button extends ScopedElementsMixin(LitElement) {
         `;
     }
 }
+
+export class LoadingButton extends ScopedElementsMixin(LitElement) {
+    constructor() {
+        super();
+        this.value = "";
+        this.type = "";
+        this.loading = false;
+        this.disabled = false;
+    }
+
+    static get scopedElements() {
+        return {
+            'dbp-mini-spinner': MiniSpinner,
+        };
+    }
+
+    static get properties() {
+        return {
+            value: { type: String },
+            type: { type: String },
+            loading: { type: Boolean },
+            disabled: { type: Boolean, reflect: true },
+        };
+    }
+
+    start() {
+        this.loading = true;
+        this.disabled = true;
+    }
+
+    stop() {
+        this.loading = false;
+        this.disabled = false;
+    }
+
+    static get styles() {
+        // language=css
+        return css`
+            ${commonStyles.getThemeCSS()}
+            ${commonStyles.getButtonCSS()}
+
+            .spinner {
+                padding-left: 0.5em;
+                min-width: 16px;
+            }
+
+            .loading-container {
+                display: flex;
+                align-items: baseline;
+            }
+
+            .label {
+                white-space: nowrap;
+                overflow: hidden;
+                text-overflow: ellipsis;
+            }
+
+            :host {
+                display: inline-block;
+            }
+
+            .is-not-loading .label {
+                padding-left: 12px;
+                padding-right: 12px;
+            }
+        `;
+    }
+
+    render() {
+        return html`
+            <button class="button ${this.type} loading-container  ${!this.loading ? "is-not-loading" : ""}" ?disabled="${this.disabled}">
+                <div class="label">${this.value}</div> <dbp-mini-spinner class="spinner" style="display: ${this.loading ? "inline" : "none"}"></dbp-mini-spinner>
+            </button>
+        `;
+    }
+}
diff --git a/packages/common/src/mini-spinner.js b/packages/common/src/mini-spinner.js
index 67e769997b2984343db1c1ac06ad4efbe37f7c25..f03d734da7de385f3e3366becd53367421d0041d 100644
--- a/packages/common/src/mini-spinner.js
+++ b/packages/common/src/mini-spinner.js
@@ -17,6 +17,7 @@ export class MiniSpinner extends LitElement {
         return css`
         .outer {
             display: inline-block;
+            vertical-align: sub;
         }
         .inner {
             display: flex;