diff --git a/src/api/index.ts b/src/api/index.ts
index 80464f1b86cc04529c05ce63cbb16c8046c1d362..50332ccf57db71b961f0e66751faee189da05a43 100644
--- a/src/api/index.ts
+++ b/src/api/index.ts
@@ -24,7 +24,8 @@ export * from './process'
 export * from './repository'
 export * from './rights'
 export * from './search'
-export * from './selection'
+export * from './selection.js'
+export * from './selection.ts'
 export * from './transcription'
 export * from './transkribus'
 export * from './user'
diff --git a/src/api/selection.ts b/src/api/selection.ts
new file mode 100644
index 0000000000000000000000000000000000000000..551e8830ad84e793391e1c9b545746967b5ade2c
--- /dev/null
+++ b/src/api/selection.ts
@@ -0,0 +1,20 @@
+import axios from 'axios'
+import { unique } from '.'
+import { UUID } from '@/types'
+
+interface CreateDatasetElementsSelectionParameters {
+  /**
+   * ID of the dataset that will receive selected elements
+   */
+  dataset_id: UUID
+
+  /**
+   * Name of the set elements will be added to
+   */
+  set: string
+}
+
+/**
+ * Add selected elements to a corpus' dataset
+ */
+export const createDatasetElementsSelection = unique(async (corpusId: UUID, params: CreateDatasetElementsSelectionParameters) => (await axios.post(`/corpus/${corpusId}/datasets/selection/`, params)))
diff --git a/src/components/Navigation/CorpusSelection.vue b/src/components/Navigation/CorpusSelection.vue
index 8a5e9bc23c628cf8a3a507c4153dc1beca620454..dd36d15b0b786dfccf8b35e2e302c19667c935c2 100644
--- a/src/components/Navigation/CorpusSelection.vue
+++ b/src/components/Navigation/CorpusSelection.vue
@@ -39,11 +39,20 @@
             :disabled="!canCreate || null"
             class="dropdown-item"
             v-on:click="createParentModal = canCreate"
-            :title="canCreate ? 'Link selected elements to another parent folder.' : executeDisabledTitle"
+            :title="canCreate ? 'Link selected elements to another parent folder.' : createDisabledTitle"
           >
             <i class="icon-direction"></i>
             Link to another parent
           </a>
+          <a
+            :disabled="!canCreate || null"
+            class="dropdown-item"
+            v-on:click="datasetSelectionModal = canCreate"
+            :title="canCreate ? 'Add those elements to a dataset.' : createDisabledTitle"
+          >
+            <i class="icon-bookmark"></i>
+            Add to a dataset
+          </a>
           <a
             :disabled="!canCreate || null"
             class="dropdown-item"
@@ -176,6 +185,8 @@
 
     <DeleteResultsModal v-model="deleteResultsModal" :corpus-id="corpusId" selection />
 
+    <DatasetFromSelectionModal v-model="datasetSelectionModal" :corpus-id="corpusId" />
+
     <ElementList
       :elements="elements"
       max-size
@@ -192,6 +203,7 @@ import { createProcessRedirect } from '@/helpers'
 import MLClassSelect from '@/components/MLClassSelect.vue'
 import Modal from '@/components/Modal.vue'
 import DeleteResultsModal from '@/components/Process/Workers/DeleteResultsModal.vue'
+import DatasetFromSelectionModal from '@/components/Navigation/DatasetFromSelectionModal.vue'
 import ElementList from './ElementList'
 import FolderPicker from '@/components/Navigation/FolderPicker'
 
@@ -204,7 +216,8 @@ export default {
     DeleteResultsModal,
     MLClassSelect,
     Modal,
-    FolderPicker
+    FolderPicker,
+    DatasetFromSelectionModal
   },
   props: {
     corpusId: {
@@ -225,7 +238,8 @@ export default {
     moveLoading: false,
     createParentModal: false,
     createParentLoading: false,
-    pickedFolder: null
+    pickedFolder: null,
+    datasetSelectionModal: false
   }),
   mounted () {
     if (this.hasMlClasses[this.corpusId] === undefined) {
diff --git a/src/components/Navigation/DatasetFromSelectionModal.vue b/src/components/Navigation/DatasetFromSelectionModal.vue
new file mode 100644
index 0000000000000000000000000000000000000000..fd08ed755e3bb4953c6542eb6eafa89c5250dd0d
--- /dev/null
+++ b/src/components/Navigation/DatasetFromSelectionModal.vue
@@ -0,0 +1,186 @@
+<template>
+  <Modal
+    :model-value="modelValue"
+    v-on:update:model-value="updateModelValue"
+    :title="truncateLong(title)"
+  >
+    <div v-if="availableDatasets === null" class="loader mx-auto is-size-1"></div>
+    <div v-else-if="availableDatasets?.length === 0" class="notification is-warning">
+      <p>No dataset available.</p>
+      <p>
+        You can create one from the
+        <router-link :to="{ name: 'corpus-update', params: { corpusId } }" class="has-text-weight-semibold">
+          corpus details page
+        </router-link>
+        .
+      </p>
+    </div>
+    <form v-else v-on:submit.prevent="addToSelection">
+      <div class="field is-horizontal">
+        <div class="field-label is-normal">
+          <label class="label">Dataset</label>
+        </div>
+        <div class="field-body">
+          <div class="field">
+            <div class="control">
+              <span class="select is-fullwidth">
+                <select
+                  v-model="selectedDataset"
+                  :disabled="loading ?? null"
+                >
+                  <option :value="null" selected disabled>—</option>
+                  <template v-if="availableDatasets">
+                    <option
+                      v-for="dataset in availableDatasets"
+                      :value="dataset"
+                      :key="dataset.id"
+                      :title="dataset.description"
+                    >
+                      {{ truncateLong(dataset.name) }}
+                    </option>
+                  </template>
+                </select>
+              </span>
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <div class="field is-horizontal">
+        <div class="field-label is-normal">
+          <label class="label">Set</label>
+        </div>
+        <div class="field-body">
+          <div class="field">
+            <div class="control">
+              <span class="select is-fullwidth">
+                <select
+                  v-model="set"
+                  :disabled="(!selectedDataset || loading) ?? null"
+                  :title="selectedDataset ? `Set elements will be added to on dataset ${selectedDataset.name}` : 'Please select a dataset first' "
+                >
+                  <option :value="null" selected disabled>—</option>
+                  <template v-if="selectedDataset?.sets">
+                    <option
+                      v-for="value in selectedDataset.sets"
+                      :value="value"
+                      :key="value"
+                    >
+                      {{ value }}
+                    </option>
+                  </template>
+                </select>
+              </span>
+            </div>
+          </div>
+        </div>
+      </div>
+    </form>
+
+    <template v-slot:footer="{ close }">
+      <button
+        class="button is-info"
+        :class="{ 'is-loading': loading }"
+        type="submit"
+        :disabled="!canAdd"
+        :title="canAdd ? 'Add selected elements to the dataset' : 'Please select a dataset and related set'"
+        v-on:click="addToSelection"
+      >
+        Add elements
+      </button>
+      <button class="button ml-auto" v-on:click="close">Cancel</button>
+    </template>
+  </Modal>
+</template>
+
+<script lang="ts">
+import {
+  mapState as mapVuexState,
+  mapActions as mapVuexActions
+} from 'vuex'
+import { corporaMixin, truncateMixin } from '@/mixins'
+import { UUID_REGEX } from '@/config'
+import { Dataset, UUID } from '@/types'
+import Modal from '@/components/Modal.vue'
+import { defineComponent, PropType } from 'vue'
+
+export default defineComponent({
+  mixins: [
+    corporaMixin,
+    truncateMixin
+  ],
+  components: {
+    Modal
+  },
+  emits: {
+    'update:modelValue': (value: boolean) => typeof value === 'boolean'
+  },
+  props: {
+    modelValue: {
+      type: Boolean,
+      default: false
+    },
+    /**
+     * Id of the corpus to delete results on
+     */
+    corpusId: {
+      type: String as PropType<UUID>,
+      validator: value => typeof value === 'string' && UUID_REGEX.test(value),
+      required: true
+    }
+  },
+  data: () => ({
+    loading: false,
+    /**
+     * ID of the dataset that will receive selected elements
+     */
+    selectedDataset: null as Dataset | null,
+    /**
+     * Name of the set elements will be added to
+     */
+    set: null as string | null
+  }),
+  computed: {
+    ...mapVuexState('corpora', ['corpusDatasets']),
+    title (): string {
+      return `Add ${this.corpus?.name} selection to a dataset`
+    },
+    canAdd (): boolean {
+      return this.selectedDataset !== null && this.set !== null
+    },
+    availableDatasets (): Dataset[] | null {
+      return this.corpusDatasets?.[this.corpusId] ?? null
+    }
+  },
+  methods: {
+    ...mapVuexActions('corpora', ['listCorpusDatasets', 'addDatasetElementsSelection']),
+    updateModelValue (value: boolean) { this.$emit('update:modelValue', value) },
+    async addToSelection () {
+      if (!this.canAdd) return
+
+      this.loading = true
+      try {
+        await this.addDatasetElementsSelection({
+          corpusId: this.corpusId,
+          params: {
+            dataset_id: this.selectedDataset?.id,
+            set: this.set
+          }
+        })
+        this.selectedDataset = null
+        this.set = null
+        this.$emit('update:modelValue', false)
+      } finally {
+        this.loading = false
+      }
+    }
+  },
+  watch: {
+    modelValue (newValue: boolean) {
+      if (newValue && this.availableDatasets === null) {
+        this.listCorpusDatasets({ corpusId: this.corpusId })
+      }
+    }
+  }
+})
+</script>
diff --git a/src/store/corpora.js b/src/store/corpora.js
index f00143acca9d1a1efdaa10921fe5f0031db1a394..5f6aa688137af7bf0d91b4f077988bcbb6576192 100644
--- a/src/store/corpora.js
+++ b/src/store/corpora.js
@@ -419,6 +419,17 @@ export const actions = {
     }
   },
 
+  // Add selected elements to a dataset of the same corpus
+  async addDatasetElementsSelection ({ commit }, { corpusId, params }) {
+    try {
+      await api.createDatasetElementsSelection(corpusId, params)
+      commit('notifications/notify', { type: 'success', text: 'Elements have been added to the dataset.' }, { root: true })
+    } catch (err) {
+      commit('notifications/notify', { type: 'error', text: errorParser(err) }, { root: true })
+      throw err
+    }
+  },
+
   async listExports ({ commit }, { corpusId, ...payload }) {
     try {
       commit('setExports', await api.listExports(corpusId, removeEmptyStrings(payload)))
diff --git a/tests/unit/store/corpora.spec.js b/tests/unit/store/corpora.spec.js
index 40465fa10a8f6e2e10fd021be1e750bc54b1df4e..e647c104c432a3da72a4558632543dd7934afe2c 100644
--- a/tests/unit/store/corpora.spec.js
+++ b/tests/unit/store/corpora.spec.js
@@ -2229,6 +2229,34 @@ describe('corpora', () => {
       })
     })
 
+    describe('addDatasetElementsSelection', () => {
+      it('adds elements from a selection to a dataset', async () => {
+        mock.onPost('/corpus/corpusid/datasets/selection/', { dataset_id: 'datasetid', set: 'test' }).reply(204)
+
+        const params = { dataset_id: 'datasetid', set: 'test' }
+        await store.dispatch('corpora/addDatasetElementsSelection', { corpusId: 'corpusid', params })
+
+        assert.deepStrictEqual(store.history, [
+          { action: 'corpora/addDatasetElementsSelection', payload: { corpusId: 'corpusid', params } },
+          { mutation: 'notifications/notify', payload: { type: 'success', text: 'Elements have been added to the dataset.' } }
+        ])
+      })
+
+      it('throw errors', async () => {
+        mock.onPost('/corpus/corpusid/datasets/selection/', { dataset_id: 'datasetid', set: 'test' }).reply(400)
+
+        const params = { dataset_id: 'datasetid', set: 'test' }
+        await assertRejects(
+          async () => await store.dispatch('corpora/addDatasetElementsSelection', { corpusId: 'corpusid', params })
+        )
+
+        assert.deepStrictEqual(store.history, [
+          { action: 'corpora/addDatasetElementsSelection', payload: { corpusId: 'corpusid', params } },
+          { mutation: 'notifications/notify', payload: { type: 'error', text: 'Request failed with status code 400' } }
+        ])
+      })
+    })
+
     describe('listExports', () => {
       it('lists exports in a corpus', async () => {
         mock.onGet('/corpus/corpusid/export/').reply(200, { count: 1, results: [exportSample] })
diff --git a/tsconfig.json b/tsconfig.json
index 3c4e82d9cc875746b66a4875cfdff25cffe20101..10c3abfe11f0e36c0b06cca5151da6662031ed56 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -5,6 +5,8 @@
     "strict": true,
     "jsx": "preserve",
     "allowJs": true,
+    "allowImportingTsExtensions": true,
+    "noEmit": true,
     "importHelpers": true,
     "moduleResolution": "node",
     "skipLibCheck": true,