diff --git a/misc/yaml_to_json.py b/misc/yaml_to_json.py
index a7d5bd62a7a1ccc50766b797ef6710466e9bee11..e77e5efc56b2cea39b0a7b6f90236fb5b39da24e 100755
--- a/misc/yaml_to_json.py
+++ b/misc/yaml_to_json.py
@@ -6,4 +6,4 @@ import json
 import yaml
 
 with open(sys.argv[1], 'r') as infile:
-    print(json.dumps(yaml.load(infile)))
+    print(json.dumps(yaml.safe_load(infile)))
diff --git a/src/core/js/form_elements.js b/src/core/js/form_elements.js
index d4cd4234a28953140fcc1f62104e2c43a3460cdb..006edcfa0b89903e2f566d73c459c5fb51bc4fd5 100644
--- a/src/core/js/form_elements.js
+++ b/src/core/js/form_elements.js
@@ -118,7 +118,7 @@ var form_elements = new function () {
     this.get_cache_value = function (field) {
         var ret = $(field)
             .find(":input")
-            .val();
+            .val()
         if (!ret) {
             return null;
         } else {
@@ -293,12 +293,15 @@ var form_elements = new function () {
         if (typeof desc == "undefined") {
             desc = entity_id;
         }
-        var opt_str = '<option value="' + entity_id + '">' + desc +
+        return form_elements._make_option(entity_id, desc);
+    }
+
+    this._make_option = function(value, label) {
+        const opt_str = '<option value="' + value + '">' + label +
             "</option>";
         return $(opt_str)[0];
     }
 
-
     /**
      * (Re-)set this module's functions to standard implementation.
      */
@@ -333,12 +336,7 @@ var form_elements = new function () {
                 caosdb_utils.assert_type(make_value, "function",
                     "param `make_value`");
             }
-            const ret = $('<select class="selectpicker form-control" title="Nothing selected"/>');
-            if (multiple) {
-                ret.attr("multiple", "");
-            } else {
-                ret.append('<option style="display: none" selected="selected" value="" disabled="disabled"></option>');
-            }
+            const ret = $(form_elements._make_select(multiple));
             for (let entity of entities) {
                 this.logger.trace("add option", entity);
                 let entity_id = getEntityID(entity);
@@ -351,6 +349,16 @@ var form_elements = new function () {
             return ret[0];
         }
 
+        this._make_select = function (multiple) {
+            const ret = $('<select class="selectpicker form-control" title="Nothing selected"/>');
+            if (multiple) {
+                ret.attr("multiple", "");
+            } else {
+                ret.append('<option style="display: none" selected="selected" value="" disabled="disabled"></option>');
+            }
+            return ret[0];
+        }
+
         /**
          * Configuration object for a drop down menu for selecting references.
          * `make_reference_drop_down` generates such a drop down menu using a
@@ -673,6 +681,8 @@ var form_elements = new function () {
             field = await this.make_range_input(config);
         } else if (type === "reference_drop_down") {
             field = this.make_reference_drop_down(config);
+        } else if (type === "select") {
+            field = this.make_select_input(config);
         } else if (type === "subform") {
             // TODO handle cache and required for subforms
             return await this.make_subform(config);
@@ -1223,6 +1233,32 @@ var form_elements = new function () {
     }
 
 
+    /**
+     * Return a select field.
+     *
+     * @param {form_elements.input_config} config
+     * @returns {HTMLElement} a select field.
+     */
+    this.make_select_input = function (config) {
+        const options = config.options;
+        const multiple = config.multiple;
+        const select = $(form_elements._make_select(multiple));
+        for (let option of options) {
+            select.append(form_elements._make_option(option.value, option.label));
+        }
+
+        const ret = $(form_elements._make_field_wrapper(config.name));
+        const label = form_elements._make_input_label_str(config);
+        select.change(function () {
+            ret[0].dispatchEvent(form_elements.field_changed_event);
+        });
+
+        const input_col = $('<div class="caosdb-f-property-value col-sm-9"/>');
+        input_col.append(select);
+        return ret.append(label, input_col)[0];
+    }
+
+
     /**
      * Return a checkbox input field.
      *
diff --git a/test/core/js/modules/form_elements.js.js b/test/core/js/modules/form_elements.js.js
index f8bf1ed1ac1495a8a3688aeb7b0cce387c8b69fb..1fc734cd26881416338add2b7ca4a243495829a9 100644
--- a/test/core/js/modules/form_elements.js.js
+++ b/test/core/js/modules/form_elements.js.js
@@ -628,4 +628,52 @@ QUnit.test("make_alert - remember", async function(assert) {
     assert.equal(typeof _alert, "undefined", "alert was not created, proceed callback was called third time");
 });
 
+QUnit.test("make_select_input", function(assert) {
+    const config = {
+        name: "sex", label: "Sex", multiple: true, options: [
+            {"value": "f", "label": "female"},
+            {"value": "d", "label": "diverse"},
+            {"value": "m", "label": "male"},
+        ],
+    }
+    const select = $(form_elements.make_select_input(config));
+    assert.equal(select.find("select").length, 1, "select input there");
+    assert.equal(select.find("select option").length, 3, "three options there");
+});
+
+QUnit.test("select_input caching", async function (assert) {
+    const config = {
+      "name": "test-form",
+      "fields": [
+            {
+                type: "select",
+                required: true,
+                cached: true,
+                name: "sex",
+                label: "Sex",
+                options: [
+                    {"value": "f", "label": "female"},
+                    {"value": "d", "label": "diverse"},
+                    {"value": "m", "label": "male"},
+                ],
+            },
+        ],
+    }
+    const form_wrapper = $(form_elements.make_form(config));
+    await sleep(500);
+    const form = form_wrapper.find("form");
+    assert.equal(form.find("select").length, 1);
+    assert.equal(xml2str(form[0]), "");
+
+
+    var cache = {};
+    var field = $(form_elements.get_fields(form[0], "sex"));
+    field.find("select").val("f");
+    assert.equal(form_elements.get_cache_value(field[0]), "f", "value set");
+    assert.equal(form_elements.get_cache_key(form[0], field[0]), "form_elements.cache.test-form.sex", "cache key correct");
+
+    form_elements.cache_form(cache, form[0]);
+    assert.equal(cache[form_elements.get_cache_key(form[0], field[0])], "f");
+});
+
 }