Here's how to do with createApp in Vue 3, but the context (stores, plugins, directives...) will not be kept.
Copy// DialogService.js
import { createApp } from 'vue';
export default {
alert(text) {
const mountEl = document.createElement('div');
document.body.appendChild(mountEl);
const dialog = createApp({ extends: DialogComponentDef }, {
// props
text,
// events are passed as props here with on[EventName]
onClose() {
mountEl.parentNode.removeChild(mountEl);
dialog.unmount();
dialog = null;
},
});
dialog.mount(mountEl);
},
};
To keep the context, there's something more complicated that can be seen here with h and render Vue methods : https://github.com/vuejs/vue-next/issues/2097#issuecomment-709860132
Here's how to do with createApp in Vue 3, but the context (stores, plugins, directives...) will not be kept.
Copy// DialogService.js
import { createApp } from 'vue';
export default {
alert(text) {
const mountEl = document.createElement('div');
document.body.appendChild(mountEl);
const dialog = createApp({ extends: DialogComponentDef }, {
// props
text,
// events are passed as props here with on[EventName]
onClose() {
mountEl.parentNode.removeChild(mountEl);
dialog.unmount();
dialog = null;
},
});
dialog.mount(mountEl);
},
};
To keep the context, there's something more complicated that can be seen here with h and render Vue methods : https://github.com/vuejs/vue-next/issues/2097#issuecomment-709860132
I would recommend using the mount-vue-component. It's lightweight and easy to use. Code example:
Copyimport MyComponent1 from './MyComponent1.vue'
import MyComponent2 from './MyComponent2.vue'
import { mount } from 'mount-vue-component'
let dynamicComponent = mount(someCondition ? MyComponent1 : MyComponent2, { props: { <someProperties...> }, app: MyVueApp })
Videos
I use Vue3 with Vite.
I have a dozen of components, all defined as SFCs and using the composition API and the script setup syntax. They all look pretty similar to this:
<template>
<p>My component</p>
</template>
<script setup>
const props = defineProps({
propA: {
type: String,
default: ''
}
});
</script>I am trying to create instances of these components, and add them to my app, programmatically. And so far, all the methods I have read about online, fail miserably.
The most promising seem to be the one described in this comment in an issue of the official Vue GitHub. Here is how I implemented it:
var myComponentInstance = defineComponent({
extends: myComponent,
data: () => ({
props: {
propA: 'ABCDE'
}
})
});
createApp(TitleComponent).mount(this.$refs.container);But even though I think I'm doing what's expected, it fails miserably and I get tons of JS errors.
Is there an easy way to create instances of various Components (providing data via props) and mount them in my app, reliably?
I figured how to do it using <component :is="type" /> and wrote this exemple.
It turns out that Vue has <component :is="yourComponentType"> which does exactly what I was hoping to accomplish if you throw it into a v-for loop. Documents here.
You can use Async components to retrieve a component via an API.
I've tested with GraphQL via Axios but it should work with any REST service.
The main component looks like that:
<template>
<div>
<h1>Test page</h1>
<div><button @click="clicked = true">Load component</button></div>
<async-component v-if="clicked" />
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
clicked: false,
};
},
components: {
'async-component': () => axios.post('http://localhost:5000/graphql', { query: `
{
asyncComponentByRowId(rowId: 1) {
component
content
}
}
`,
}).then((response) => {
const comp = response.data.data.asyncComponentByRowId.content;
// eval can be harmful
return eval(`(${comp})`);
}),
},
};
</script>
The retrieved component is in the following format:
{
"data": {
"asyncComponentByRowId": {
"component": "my-async-component",
"content": "{\r\n\ttemplate: '<div>{{ msg }}</div>',\r\n\tdata: function() {\r\n\t\treturn {\r\n\t\t\tmsg: 'Async component works!'\r\n\t\t};\r\n\t}\r\n}"
}
}
}
The decoded data.asyncComponentByRowId.content property is a string representing a JavaScript object:
{
template: '<div>{{ msg }}</div>',
data: function() {
return {
msg: 'Async component works!'
};
}
}
When the button is pressed, the component is shown after being downloaded from the API asynchronously.
The only problem is that I'm using eval to decode the object.
Result:

import {defineComponent,createApp} from 'vue'
buttonView = defineComponent({
extends: Button, data() {
return {
type: "1111"
}
}
})
const div = document.createElement('div');
this.$refs.container.appendChild(div);
createApp(buttonView ).mount(div)
This works for me, using options API, in a method create a component
import { defineComponent } from "vue";
createComponent() {
var component = {
data() {
return {
hello:'world',
}
},
template:`<div>{{hello}}</div>`
}
var instance = defineComponent(component);
}
Use it within your template once you've instantiated it
<component :is="instance" v-if="instance"/>
I'm porting some old code that is basically this:
import Modal from 'Modal.vue'
import Vue from 'vue'
var ComponentClass = Vue.extend(Modal)
var instance = new ComponentClass({
propsData: { title: 'title' }
})
instance.$mount() // pass nothing
this.$refs.container.appendChild(instance.$el)
I can't seem to find a way to get this working using Vue3.
Vue.extend has been removed, as far as I can see there's now defineComponent, but it does not seem to work the same way.
I get the following error when I just try and replace it 1-1: TypeError: ComponentClass is not a constructor
Has anyone tried something similar, or know how to fix this?
1) Since you're manually instantiating that component and it doesn't belong to your main app's component tree, the store won't be automatically injected into it from your root component. You'll have to manually provide the store to the constructor when you instantiate the component ..
import ProjectRow from "./ProjectRow.vue";
import Vue from "vue";
import store from "../store";
let ProjectRowClass = Vue.extend(ProjectRow);
let ProjectRowInstance = new ProjectRowClass({ store });
2) In a Vue Single File Component (SFC), outside of the default export this doesn't refer to the Vue instance, so you don't have access to $refs or any other Vue instance property/method. To gain access to the Vue instance you'll need to move this line this.$refs.container.appendChild(instance.$el) somewhere inside the default export, for example in the mounted hook or inside one of your methods.
See this CodeSandbox for an example of how you may go about this.
This is another way to instantiate a component in Vue.js, you can use two different root elements.
// Instantiate you main app
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
//
// Then instantiate your component dynamically
//
// Create a component or import it.
const Hello = {
props: ['text'],
template: '<div class="hello">{{ text }}</div>',
};
// Create a componentClass by Vue.
const HelloCtor = Vue.extend(Hello);
// Use componentClass to instantiate your component.
const vm = new HelloCtor({
propsData: {
text: 'HI :)'
}
})
// then mount it to an element.
.$mount('#mount');
If component is already mounted ie defined as a component globally using Vue(tag,constructor) then simply adding a new instance of component importantly using parent keyword to define parent of component instance will do the trick as below :
NB : As of vue js V-1.0.12, $addChild method was removed
components: {
'extform-input' : ExtformInput
},
methods : {
changeType: function() {
var self = this
var Child = this.$options.components['extform-input'];
var child = new Child({
el: this.$el.querySelector('.child-host'), \\ define the el of component
parent: this, \\ define parent of component
});
}
}
See codepen demo http://codepen.io/obonyojimmy/pen/ONwKZX
You can't dynamically instantiate components in Vue js. Here is a discussion about the subject, and a similar question (I did that question). But, even if you can't dynamically add components, you can do what you want to do, in a different way. Instead of adding the child, you have to show it adding it to the DOM, if you want to add a single component use v-if (notiche that you are not hidding/showing an element, you are adding/removing from the DOM). And if you want to add a variable number of component on the fly, use v-for. The details are on the referenced question for the v-for way