diff --git a/rollup.config.js b/rollup.config.js
index f9f91a8f4b0db466c7bb15dc6683e3096f6c7f8d..19fd44085b0af3c34aa179fd185be48d7ba2de03 100644
--- a/rollup.config.js
+++ b/rollup.config.js
@@ -272,7 +272,7 @@ Dependencies:
                 {src: 'assets/manifest.json', dest: 'dist', rename: pkg.name + '.manifest.json'},
                 {src: 'assets/*.metadata.json', dest: 'dist'},
                 {src: 'node_modules/vpu-common/assets/icons/*.svg', dest: 'dist/local/vpu-common/icons'},
-                {src: 'node_modules/tabulator-tables/dist/css', dest: 'dist/local/' + pkg.name + '/tabulator-tables'},
+                {src: 'node_modules/tabulator-tables/dist/css', dest: 'dist/local/vpu-fileupload/tabulator-tables'},
             ],
         }),
         useBabel && babel({
diff --git a/src/vpu-nextcloud-file-picker.js b/src/vpu-nextcloud-file-picker.js
deleted file mode 100644
index ec84c83dc535c6f134a7d42e5b53bd20a1ae7c44..0000000000000000000000000000000000000000
--- a/src/vpu-nextcloud-file-picker.js
+++ /dev/null
@@ -1,253 +0,0 @@
-import {createI18nInstance} from './i18n.js';
-import {css, html} from 'lit-element';
-import {ScopedElementsMixin} from '@open-wc/scoped-elements';
-import VPULitElement from 'vpu-common/vpu-lit-element';
-import {MiniSpinner} from 'vpu-common';
-import * as commonUtils from 'vpu-common/utils';
-import * as commonStyles from 'vpu-common/styles';
-import { createClient } from "webdav/web";
-import {classMap} from 'lit-html/directives/class-map.js';
-import {humanFileSize} from "vpu-common/i18next";
-import Tabulator from 'tabulator-tables';
-
-const i18n = createI18nInstance();
-
-/**
- * NextcloudFilePicker web component
- */
-export class NextcloudFilePicker extends ScopedElementsMixin(VPULitElement) {
-    constructor() {
-        super();
-        this.lang = 'de';
-        this.authUrl = '';
-        this.webDavUrl = '';
-        this.loginWindow = null;
-        this.isPickerActive = false;
-        this.statusText = "";
-        this.lastDirectoryPath = "/";
-        this.directoryPath = "/";
-        this.webDavClient = null;
-        this.tabulatorTable = null;
-
-        this._onReceiveWindowMessage = this.onReceiveWindowMessage.bind(this);
-    }
-
-    static get scopedElements() {
-        return {
-            'vpu-mini-spinner': MiniSpinner,
-        };
-    }
-
-    /**
-     * See: https://lit-element.polymer-project.org/guide/properties#initialize
-     */
-    static get properties() {
-        return {
-            lang: { type: String },
-            authUrl: { type: String, attribute: "auth-url" },
-            webDavUrl: { type: String, attribute: "web-dav-url" },
-            isPickerActive: { type: Boolean, attribute: false },
-            statusText: { type: String, attribute: false },
-            directoryPath: { type: String, attribute: false },
-        };
-    }
-
-    update(changedProperties) {
-        changedProperties.forEach((oldValue, propName) => {
-            switch (propName) {
-                case "lang":
-                    i18n.changeLanguage(this.lang);
-                    break;
-            }
-        });
-
-        super.update(changedProperties);
-    }
-
-    disconnectedCallback() {
-        window.removeEventListener('message', this._onReceiveWindowMessage);
-        super.disconnectedCallback();
-      }
-
-    connectedCallback() {
-        super.connectedCallback();
-
-        this.updateComplete.then(() => {
-            // see: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
-            window.addEventListener('message', this._onReceiveWindowMessage);
-
-            // http://tabulator.info/docs/4.7
-            // TODO: format size and lastmod
-            // TODO: translation of column headers
-            // TODO: mime type icon
-            this.tabulatorTable = new Tabulator(this._("#directory-content-table"), {
-                layout: "fitDataStretch",
-                selectable: true,
-                columns: [
-                    {title: "Filename", field: "basename"},
-                    {title: "Size", field: "size", formatter: (cell, formatterParams, onRendered) => {
-                            return cell.getRow().getData().type === "directory" ? "" : humanFileSize(cell.getValue());}},
-                    {title: "Type", field: "type"},
-                    {title: "Mime", field: "mime"},
-                    {title: "Last modified", field: "lastmod", sorter: "date"},
-                ],
-                rowClick: (e, row) => {
-                    const data = row.getData();
-
-                    switch(data.type) {
-                        case "directory":
-                            this.directoryClicked(e, data);
-                            break;
-                        case "file":
-                            console.log("file selected", data);
-                            break;
-                    }
-                },
-            });
-        });
-    }
-
-    openFilePicker() {
-        // TODO: translation
-        this.statusText = "Auth in progress";
-        this.loginWindow = window.open(this.authUrl, "Nextcloud Login",
-            "width=400,height=400,menubar=no,scrollbars=no,status=no,titlebar=no,toolbar=no");
-    }
-
-    onReceiveWindowMessage(event) {
-        const data = event.data;
-        console.log("data", data);
-
-        if (data.type === "webapppassword") {
-            this.loginWindow.close();
-            // alert("Login name: " + data.loginName + "\nApp password: " + data.token);
-
-            const apiUrl = this.webDavUrl + "/" + data.loginName;
-
-            // https://github.com/perry-mitchell/webdav-client/blob/master/API.md#module_WebDAV.createClient
-            this.webDavClient = createClient(
-                apiUrl,
-                {
-                    username: data.loginName,
-                    password: data.token
-                }
-            );
-
-            this.loadDirectory("/");
-        }
-    }
-
-    /**
-     * Loads the directory from WebDAV
-     *
-     * @param path
-     */
-    loadDirectory(path) {
-        // TODO: translation
-        this.statusText = "Loading directory from Nextcloud: " + path;
-        this.lastDirectoryPath = this.directoryPath;
-        this.directoryPath = path;
-
-        // https://github.com/perry-mitchell/webdav-client#getdirectorycontents
-        this.webDavClient
-            .getDirectoryContents(path, {details: true})
-            .then(contents => {
-                console.log("contents", contents);
-                this.statusText = "";
-                this.tabulatorTable.setData(contents.data);
-                this.isPickerActive = true;
-            }).catch(error => {
-            console.error(error.message);
-            this.statusText = error.message;
-            this.isPickerActive = false;
-        });
-    }
-
-    directoryClicked(event, file) {
-        this.loadDirectory(file.filename);
-        event.preventDefault();
-    }
-
-    downloadFiles(files) {
-        files.forEach((fileData) => this.downloadFile(fileData));
-    }
-
-    downloadFile(fileData) {
-        this.statusText = "Loading " + fileData.filename + "...";
-
-        // https://github.com/perry-mitchell/webdav-client#getfilecontents
-        this.webDavClient
-            .getFileContents(fileData.filename)
-            .then(contents => {
-                // create file to send via event
-                const file = new File([contents], fileData.basename, { type: fileData.mime });
-                console.log("binaryFile", file);
-
-                // send event
-                const data = {"file": file, "data": fileData};
-                const event = new CustomEvent("vpu-nextcloud-file-picker-file-downloaded",
-                    { "detail": data, bubbles: true, composed: true });
-                this.dispatchEvent(event);
-
-                this.statusText = "";
-            }).catch(error => {
-                console.error(error.message);
-                this.statusText = error.message;
-            });
-    }
-
-    /**
-     * Returns the parent directory path
-     *
-     * @returns {string} parent directory path
-     */
-    getParentDirectoryPath() {
-        let path = this.directoryPath.replace(/\/$/, "");
-        path = path.replace(path.split("/").pop(), "").replace(/\/$/, "");
-
-        return (path === "") ? "/" : path;
-    }
-
-    static get styles() {
-        // language=css
-        return css`
-            ${commonStyles.getGeneralCSS()}
-            ${commonStyles.getButtonCSS()}
-
-            .block {
-                margin-bottom: 10px;
-            }
-        `;
-    }
-
-    render() {
-        commonUtils.initAssetBaseURL('vpu-tabulator-table');
-        const tabulatorCss = commonUtils.getAssetURL('local/vpu-signature/tabulator-tables/css/tabulator.min.css');
-
-        return html`
-            <link rel="stylesheet" href="${tabulatorCss}">
-            <div class="block">
-                <button class="button"
-                        title="${i18n.t('nextcloud-file-picker.open-nextcloud-file-picker')}"
-                        @click="${async () => { this.openFilePicker(); } }">${i18n.t('nextcloud-file-picker.open')}</button>
-            </div>
-            <div class="block ${classMap({hidden: this.statusText === ""})}">
-                <vpu-mini-spinner style="font-size: 0.7em"></vpu-mini-spinner>
-                ${this.statusText}
-            </div>
-            <div class="block ${classMap({hidden: !this.isPickerActive})}">
-                <h2>${this.directoryPath}</h2>
-                <button class="button is-small"
-                        title="${i18n.t('nextcloud-file-picker.folder-last')}"
-                        @click="${() => { this.loadDirectory(this.lastDirectoryPath); }}">&#8678;</button>
-                <button class="button is-small"
-                        title="${i18n.t('nextcloud-file-picker.folder-up')}"
-                        @click="${() => { this.loadDirectory(this.getParentDirectoryPath()); }}">&#8679;</button>
-                <table id="directory-content-table"></table>
-                <button class="button"
-                        title="${i18n.t('nextcloud-file-picker.folder-up')}"
-                        @click="${() => { this.downloadFiles(this.tabulatorTable.getSelectedData()); }}">${i18n.t('nextcloud-file-picker.select-files')}</button>
-            </div>
-        `;
-    }
-}
diff --git a/src/vpu-qualified-signature-pdf-upload.js b/src/vpu-qualified-signature-pdf-upload.js
index aebf6c29b6345405fdba5d8b829a2dab709ad8ea..630e7e06a615e6c23e1358723c8c10a7ae8e3c1c 100644
--- a/src/vpu-qualified-signature-pdf-upload.js
+++ b/src/vpu-qualified-signature-pdf-upload.js
@@ -13,7 +13,6 @@ import {classMap} from 'lit-html/directives/class-map.js';
 import {FileUpload} from 'vpu-file-upload';
 import JSONLD from "vpu-common/jsonld";
 import {TextSwitch} from './textswitch.js';
-import {NextcloudFilePicker} from "./vpu-nextcloud-file-picker";
 import nextcloudWebAppPasswordURL from 'consts:nextcloudWebAppPasswordURL';
 import nextcloudWebDavURL from 'consts:nextcloudWebDavURL';
 import buildinfo from 'consts:buildinfo';
@@ -65,7 +64,6 @@ class QualifiedSignaturePdfUpload extends ScopedElementsMixin(VPUSignatureLitEle
           'vpu-mini-spinner': MiniSpinner,
           'vpu-button': Button,
           'vpu-textswitch': TextSwitch,
-          'vpu-nextcloud-file-picker': NextcloudFilePicker,
         };
     }
 
@@ -923,6 +921,8 @@ class QualifiedSignaturePdfUpload extends ScopedElementsMixin(VPUSignatureLitEle
                     <div class="control">
                         <vpu-fileupload id="file-upload"
                             allowed-mime-types="application/pdf"
+                            nextcloud-auth-url="${showTestNextcloudFilePicker ? nextcloudWebAppPasswordURL : ""}"
+                            nextcloud-web-dav-url="${nextcloudWebDavURL}"
                             decompress-zip
                             always-send-file
                             deferred
@@ -1078,14 +1078,6 @@ class QualifiedSignaturePdfUpload extends ScopedElementsMixin(VPUSignatureLitEle
             <div class="${classMap({hidden: !this.isLoading()})}">
                 <vpu-mini-spinner></vpu-mini-spinner>
             </div>
-            <!-- File picker test -->
-            <vpu-nextcloud-file-picker class="${classMap({hidden: !showTestNextcloudFilePicker})}"
-                                       lang="${this.lang}"
-                                       auth-url="${nextcloudWebAppPasswordURL}"
-                                       web-dav-url="${nextcloudWebDavURL}"
-                                       @vpu-nextcloud-file-picker-file-downloaded="${(event) => {
-                                           this._("#file-upload").queueFile(event.detail.file);
-                                       }}"></vpu-nextcloud-file-picker>
         `;
     }
 }
diff --git a/vendor/file-upload b/vendor/file-upload
index c8418bfd61cee7f966810c1c0ca2efd0d50825b9..045793134dfcb189a0e6f1cbb28807b6f14a1cd7 160000
--- a/vendor/file-upload
+++ b/vendor/file-upload
@@ -1 +1 @@
-Subproject commit c8418bfd61cee7f966810c1c0ca2efd0d50825b9
+Subproject commit 045793134dfcb189a0e6f1cbb28807b6f14a1cd7