diff --git a/src/components/TrainerField.vue b/src/components/TrainerField.vue
new file mode 100644
index 0000000000000000000000000000000000000000..a1e233ee2e6f3862de6a8c29af0ed0582494c1c4
--- /dev/null
+++ b/src/components/TrainerField.vue
@@ -0,0 +1,168 @@
+<template>
+  <v-dialog
+    v-model="dialog"
+  >
+    <template
+      v-slot:activator="{ on }"
+    >
+      <v-text-field
+        label="트레이너"
+        readonly
+        v-model="trainer.name"
+        v-on="on"
+      ></v-text-field>
+    </template>
+    <v-card>
+      <v-card-title>트레이너 선택</v-card-title>
+      <v-card-text>
+        <v-row
+          justify="end"
+        >
+          <v-col
+            cols="12"
+            sm="4"
+            md="3"
+            lg="3"
+            xl="2"
+          >
+            <v-text-field
+              append-icon="mdi-magnify"
+              clearable
+              label="트레이너 검색"
+              v-model="trainerList.searchKeyword"
+            ></v-text-field>
+          </v-col>
+        </v-row>
+        <v-data-table
+          :headers="trainerList.headers"
+          item-key="id"
+          :items="trainerList.data"
+          :loading="isProcessing"
+          loading-text="데이터를 불러오는 중입니다."
+          no-results-text="일치하는 트레이너를 찾지 못했습니다."
+          :search="trainerList.searchKeyword"
+        >
+          <template
+            v-slot:item.action="{ item }"
+          >
+            <v-btn
+              color="success"
+              outlined
+              small
+              @click="select(item)"
+            >
+              <v-icon
+                left
+              >
+                mdi-check
+              </v-icon>
+              선택
+            </v-btn>
+          </template>
+        </v-data-table>
+      </v-card-text>
+      <v-card-actions>
+        <v-spacer></v-spacer>
+        <v-btn
+          color="secondary"
+          outlined
+          @click="close()"
+        >
+          <v-icon
+            left
+          >mdi-close</v-icon>
+          닫기
+        </v-btn>
+      </v-card-actions>
+    </v-card>
+  </v-dialog>
+</template>
+
+<script>
+import APISetting from '@/settings/api';
+
+export default {
+  name: 'TrainerField',
+
+  props: ['trainer'],
+
+  data: () => ({
+    isProcessing: false,
+    error: {
+      isError: false,
+      message: '',
+    },
+    dialog: false,
+    trainerList: {
+      headers: [
+        {
+          text: '#',
+          value: 'id',
+        },
+        {
+          text: '이름',
+          value: 'name',
+        },
+        {
+          text: '닉네임',
+          value: 'nickname',
+        },
+        {
+          text: '이메일',
+          value: 'email',
+        },
+        {
+          text: '연락처',
+          value: 'phone',
+        },
+        {
+          text: '소개',
+          value: 'bio',
+        },
+        {
+          text: '',
+          value: 'action',
+          sortable: false,
+        },
+      ],
+      data: [],
+      searchKeyword: '',
+    },
+  }),
+
+  methods: {
+    getTrainerList() {
+      this.error.isError = false;
+      this.error.message = '';
+      this.isProcessing = true;
+
+      fetch(APISetting.endpoints.trainer.list, APISetting.settings.get)
+        .then((res) => {
+          if (res.status === 200) return res.json();
+          throw new Error('알 수 없는 응답입니다.');
+        })
+        .then((json) => {
+          this.trainerList.data = json.trainers;
+        })
+        .catch((e) => {
+          this.error.message = e.message;
+          this.error.isError = true;
+        })
+        .finally(() => {
+          this.isProcessing = false;
+        });
+    },
+    select(trainer) {
+      this.$emit('update:trainer', trainer);
+      this.close();
+    },
+    close() {
+      this.dialog = false;
+    },
+  },
+
+  created() {
+    this.getTrainerList();
+  },
+};
+</script>