diff --git a/src/components/shows/NoteEditorModal.vue b/src/components/shows/NoteEditorModal.vue
index a8895a943648586e629c2b63cf5eb6063f372e2e..80dcd9c56b50823450941484cfb9b31d82c1572a 100644
--- a/src/components/shows/NoteEditorModal.vue
+++ b/src/components/shows/NoteEditorModal.vue
@@ -47,6 +47,34 @@
           </template>
         </FormGroup>
 
+        <FormGroup :label="t('noteEditor.contributors')" :errors="contributorErrors">
+          <ComboBox
+            v-model="contributors"
+            :choices="relevantHosts"
+            :close-on-select="false"
+            multiple
+            input-container-class="tw-flex tw-flex-wrap tw-gap-2 tw-w-full form-control tw-h-auto tw-min-h-[46px]"
+            input-class="tw-border-none tw-min-w-[150px] focus:tw-outline-none"
+            @search="hostSearch = $event"
+          >
+            <template #default="{ choice, ...attrs }">
+              <li v-bind="attrs">
+                {{ choice.name }}
+              </li>
+            </template>
+
+            <template #selected="{ items, deselect }">
+              <Tag
+                v-for="(host, index) in items"
+                :key="index"
+                :label="host.name"
+                removable
+                @remove="deselect(host)"
+              />
+            </template>
+          </ComboBox>
+        </FormGroup>
+
         <FormGroup :label="t('noteEditor.tags')" :errors="tagsErrors">
           <TagInput v-model="tags" />
         </FormGroup>
@@ -74,38 +102,64 @@
 
 <script lang="ts" setup>
 import { computed, ref, watchEffect } from 'vue'
+import { useStore } from 'vuex'
 import { useTextareaAutosize } from '@vueuse/core'
+
 import { useAPIObject, useServerFieldErrors } from '@/api'
 import { useI18n } from '@/i18n'
-import { useUpdatableState } from '@/util'
-import { slugify } from '@/mixins/slugify'
+import { Host, Show, TimeSlot } from '@/types'
+import { useHostStore } from '@/stores/hosts'
 import { newNote, NewNote, Note, useNoteStore } from '@/stores/notes'
+import { slugify } from '@/mixins/slugify'
+import { asyncWritableComputed, useUpdatableState } from '@/util'
 import ADialog from '@/components/generic/ADialog.vue'
 import FormGroup from '@/components/generic/FormGroup.vue'
 import FormTable from '@/components/generic/FormTable.vue'
 import ImagePicker from '@/components/images/ImagePicker.vue'
 import ServerErrors from '@/components/ServerErrors.vue'
 import TagInput from '@/components/generic/TagInput.vue'
+import ComboBox from '@/components/ComboBox.vue'
+import Tag from '@/components/generic/Tag.vue'
 
 defineOptions({ compatConfig: { MODE: 3 } })
 
 const props = defineProps<{
   modelValue: null | number
-  timeslotId: number
+  timeslot: TimeSlot
   isOpen: boolean
 }>()
 const emit = defineEmits<{
   (e: 'update:modelValue', value: number | null): void
   (e: 'show', value: boolean): void
 }>()
-const noteId = computed(() => props.modelValue)
 const { t } = useI18n()
+const store = useStore()
+const shows = computed<Show[]>(() => store.state.shows.shows)
+const show = computed(() => shows.value.find((show) => show.id === props.timeslot.showId))
+const noteId = computed(() => props.modelValue)
 const noteStore = useNoteStore()
 const { obj: storedNote } = useAPIObject(noteStore, noteId)
-const noteData = ref<Note | NewNote>(newNote(props.timeslotId))
+const noteData = ref<Note | NewNote>(newNote(props.timeslot.id, show.value))
+const { items: hosts, retrieve: retrieveHost } = useHostStore()
+const hostSearch = ref('')
+const relevantHosts = computed(() => {
+  const sanitize = (s: string) => s.replace(/\s+/g, '').toLowerCase()
+  const searchString = sanitize(hostSearch.value)
+  return hosts.filter(
+    ({ id, name }) =>
+      !noteData.value.contributorIds.includes(id) && sanitize(name).includes(searchString),
+  )
+})
 const error = ref<Error>()
-const [titleErrors, summaryErrors, contentErrors, imageErrors, tagsErrors, remainingErrors] =
-  useServerFieldErrors(error, 'title', 'summary', 'content', 'tags', 'imageId')
+const [
+  titleErrors,
+  summaryErrors,
+  contentErrors,
+  imageErrors,
+  tagsErrors,
+  contributorErrors,
+  remainingErrors,
+] = useServerFieldErrors(error, 'title', 'summary', 'content', 'tags', 'contributorIds', 'imageId')
 const tags = computed({
   get() {
     return noteData.value.tags
@@ -117,6 +171,17 @@ const tags = computed({
     noteData.value.tags = value.join(', ')
   },
 })
+const contributors = asyncWritableComputed<Host[]>([], {
+  async get() {
+    const data = await Promise.all(
+      noteData.value.contributorIds.map((id) => retrieveHost(id, undefined, { useCached: true })),
+    )
+    return data.filter((obj) => obj !== null) as Host[]
+  },
+  set(value: Host[]) {
+    noteData.value.contributorIds = value.map(({ id }) => id)
+  },
+})
 
 watchEffect(() => {
   if (storedNote.value) {
diff --git a/src/components/shows/TimeSlotRow.vue b/src/components/shows/TimeSlotRow.vue
index dad1b461673ee31e867a9fdc97ccb64098d2b97c..217cadf13ed7e595b31cb3b51558029587d88f13 100644
--- a/src/components/shows/TimeSlotRow.vue
+++ b/src/components/shows/TimeSlotRow.vue
@@ -69,7 +69,7 @@
     <NoteEditorModal
       v-model="localNoteId"
       :is-open="showNoteEditor"
-      :timeslot-id="timeslot.id"
+      :timeslot="timeslot"
       @show="showNoteEditor = $event"
     />
   </Teleport>
diff --git a/src/i18n/de.js b/src/i18n/de.js
index 528e59181b76b8064cf57cd6e0f21d00ed5086a8..1a98eedbdfdab42ea699797352e0a6190f77fe7e 100644
--- a/src/i18n/de.js
+++ b/src/i18n/de.js
@@ -337,6 +337,7 @@ export default {
     contentPlaceholder: 'Beschreibe den Inhalt der Sendung',
     image: 'Bild',
     tags: 'Schlagwörter',
+    contributors: 'Mitwirkende',
     save: 'Sendungsbeschreibung speichern',
   },
 
diff --git a/src/i18n/en.js b/src/i18n/en.js
index 9c9f216dc9903f9beda0b7a12681b698783221fb..a4cb607ba837cdf5c43dbc39a72c0dbbe3de0a8f 100644
--- a/src/i18n/en.js
+++ b/src/i18n/en.js
@@ -329,6 +329,7 @@ export default {
     contentPlaceholder: 'Describe the content of the show',
     image: 'Image',
     tags: 'Tags',
+    contributors: 'Contributors',
     save: 'Save Note',
   },
 
diff --git a/src/stores/notes.ts b/src/stores/notes.ts
index d39a7cb874c5adb3e7995b2737025340d070fd03..c8f6b3ce93cbdd44ef8292c0f22b16bec1e7b138 100644
--- a/src/stores/notes.ts
+++ b/src/stores/notes.ts
@@ -10,6 +10,7 @@ import {
   createExtendableAPI,
   createSteeringURL,
 } from '@/api'
+import { Show } from '@/types'
 
 export type Note = {
   id: number
@@ -35,7 +36,7 @@ export type NewNote = Omit<Note, ReadonlyAttrs>
 type NoteCreateData = Omit<Note, ReadonlyAttrs>
 type NoteUpdateData = Partial<Omit<Note, ReadonlyAttrs>>
 
-export function newNote(timeslotId: number): NewNote {
+export function newNote(timeslotId: number, show?: Show): NewNote {
   return {
     title: '',
     slug: '',
@@ -43,7 +44,7 @@ export function newNote(timeslotId: number): NewNote {
     content: '',
     imageId: null,
     cbaId: null,
-    contributorIds: [],
+    contributorIds: show?.hostIds ?? [],
     links: [],
     timeslotId,
     tags: '',