JSFiddle - React, Tailwind, and code Playground

HTML

<script src="https://unpkg.com/vue"></script>
<section id="app">
  <content-editor></content-editor>
</section>

<template id="content-list-template">
  <section class="content-list">
    <div v-for="(currentView, index) in views" :key="currentView.index">
      <component :is="currentView.type" :model="currentView.model" :update="updateContent(index)"></component>
      <a v-on:click="removeContent(index)">Remove</a>
    </div>
  </section>
</template>

<template id="content-editor">
  <section class="content-editor">
    <content-list :views="views" :remove="removeContentBlock" :update="updateContentBlock"></content-list>
    <button v-on:click="newContentBlock()">New Content</button>
  </section>
</template>

<template id="content-longtext">
  <div class="content-longtext">
    <textarea :value="inputData" v-on:input="updateContent"></textarea>
  </div>
</template>

<template id="content-image">
  <div class="content-image">
    <input type="file" />
  </div>
</template>

JavaScript

Vue.component('content-longtext', {
      template: '#content-longtext',
      props: {
        model: { type: String, required: true },
        update: { type: Function, required: true }
      },
      data() {
        return {
          inputData: this.model
        }
      },
      methods: {
        updateContent(event) {
          this.update(event.target.value)
        }
      },
    })

    Vue.component('content-image', {
      template: '#content-image',
    })

    Vue.component('content-list', {
      template: '#content-list-template',
      props: {
        remove: { type: Function, required: true },
        update: { type: Function, required: true },
        views: { type: Array, required: true }
      },
      methods: {
        removeContent(index) {
          this.remove(index)
        },
        updateContent(index) {
          return (content) => this.update(index, content)
        },
      },
    })

    Vue.component('content-editor', {
      template: '#content-editor',
      data() {
        return {
          views: [
            {index: 0, type: 'content-longtext', model: 'test1'},
            {index: 1, type: 'content-longtext', model: 'test2'},
            {index: 2, type: 'content-longtext', model: 'test3'},
            {index: 3, type: 'content-longtext', model: 'test4'},
            {index: 4, type: 'content-longtext', model: 'test5'},
          ],
        }
      },
      methods: {
        newContentBlock(type) {
          this.views.push({index: this.views.length, type: 'content-longtext', model: ''})
        },
        updateContentBlock(index, model) {
          this.views[index].model = model
        },
        removeContentBlock(index) {
          this.views
            .splice(index, 1)
            .map((view, index) => view.index = index)
        },
      },
    })

    let app = new Vue({
      el: '#app'
    })