JSFiddle - React, Tailwind, and code Playground
HTML
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-vue@2.0.0-rc.17/dist/bootstrap-vue.min.css">
<script src="https://cdn.jsdelivr.net/npm/bootstrap-vue@2.0.0-rc.17/dist/bootstrap-vue.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="dynamic-component-demo" class="demo">
<button
v-for="tab in tabs"
:key="tab"
:class="[ 'tab-button', { active: currentTab === tab } ]"
@click="currentTab = tab"
>{{ tab }}</button>
<component :is="currentTabComponent" class="tab">
<message v-for="n in messages[currentTab]" :value="n"></message>
</component>
<input v-model="message">
<button @click="add">add</button>
</div>
CSS
.tab-button {
padding: 6px 10px;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
border: 1px solid #ccc;
cursor: pointer;
background: #f0f0f0;
margin-bottom: -1px;
margin-right: -1px;
}
.tab-button:hover {
background: #e0e0e0;
}
.tab-button.active {
background: #e0e0e0;
}
.tab {
border: 1px solid #ccc;
padding: 10px;
}
JavaScript
Vue.component('message', {
template: `<div>{{ value }}</div>`,
props: [ 'value' ],
});
Vue.component('tab-home', {
template: '<div>Home component<slot></slot></div>',
});
Vue.component('tab-posts', {
template: '<div>Posts component<slot></slot></div>',
});
Vue.component('tab-archive', {
template: '<div>Archive component<slot></slot></div>',
});
new Vue({
el: '#dynamic-component-demo',
data: {
messages: {},
message: '',
currentTab: 'Home',
tabs: [ 'Home', 'Posts', 'Archive' ],
},
computed: {
currentTabComponent() {
return `tab-${this.currentTab.toLowerCase()}`;
},
},
methods: {
add() {
if (!this.messages[this.currentTab]) {
this.messages[this.currentTab] = [];
}
this.messages[this.currentTab].push(this.message);
this.message = '';
},
},
});