diff --git a/src/core/js/form_panel.js b/src/core/js/form_panel.js
new file mode 100644
index 0000000000000000000000000000000000000000..7fa9e9ec238fad90477c7f4682c8f5293baee6dd
--- /dev/null
+++ b/src/core/js/form_panel.js
@@ -0,0 +1,95 @@
+/*
+ * ** header v3.0
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2019 IndiScale GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * ** end header
+ */
+
+'use strict';
+
+/**
+ * form_panel module for creating a panel below the navbar where forms can be
+ * placed.
+ */
+var form_panel = new function () {
+    this.version = "0.1";
+    // TODO (henrik) why are dependencies done differently here?
+    this.dependencies = ["log", "caosdb_utils", "markdown", "bootstrap"];
+
+    /**
+     * Return a the panel which shall contain the form.
+     *
+     * Side-effects:
+     * 1. Creates the form panel if it does not exist.
+     * 2. Removes the welcome panel if present.
+     */
+    this.get_form_panel = function (panel_id, title) {
+        // remove welcome
+        $(".caosdb-f-welcome-panel").remove();
+        $(".caosdb-v-welcome-panel").remove();
+
+        var existing = $("#" + panel_id);
+        if (existing.length > 0) {
+            return existing[0];
+        }
+        const panel = $('<div id="' + panel_id + '" class="caosdb-f-form-panel container"/>');
+        const header = $('<h2 class="text-center">' + title + '</h2>');
+        panel.append(header);
+
+        // add to main panel
+        $('nav').after(panel);
+
+        return panel[0];
+    };
+
+    /**
+     * Remove the form panel from the DOM tree.
+     */
+    this.destroy_form_panel = function (panel) {
+        $(panel).remove();
+    };
+
+    /**
+     * Creates a callback function that toggles the form panel which
+     */
+    this.create_show_form_callback = function (panel_id, title, form_config) {
+        return (e) => {
+            form_panel.logger.trace("enter show_form_panel", e);
+
+            const panel = $(form_panel.get_form_panel(panel_id, title));
+            if (panel.find("form").length === 0) {
+                const form = form_elements.make_form(form_config);
+                panel.append(form);
+
+                form.addEventListener("caosdb.form.cancel",
+                    (e) => form_panel.destroy_form_panel(panel),
+                    true
+                );
+            }
+        }
+    };
+    const init = function () {
+    }
+    return {
+        init: init,
+    };
+
+}
+
+$(document).ready(function () {
+    caosdb_modules.register(form_panel);
+});