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

Answer from darkylmnx on Stack Overflow
🌐
Reddit
reddit.com › r/vuejs › creating components programmatically?
r/vuejs on Reddit: Creating components programmatically?
December 21, 2022 -

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.

Discussions

How to programmatically create Vue Components indirectly
I'm attempting to add components programatically to a page in my Vue Single file Component which works beautifully if you know what you'd like to do ahead of time. In my case, the components and th... More on stackoverflow.com
🌐 stackoverflow.com
Programatically create and mount a component instance
What problem does this feature solve? With vue 2.x, the Vue.component() method did return a component constructor that could be used to programatically create an instance of that component: const M... More on github.com
🌐 github.com
7
August 6, 2020
vue.js - vue2 - Programmatically create component and slots - Stack Overflow
When creating vue (2.17.4) components programmatically, it does not take data from the domnode. If you use new Vue() it does. For components created using Vue.component or Vue.extend, the props and More on stackoverflow.com
🌐 stackoverflow.com
Vue3 Creating Component Instances Programmatically
What problem does this feature solve? In vue2 it was be easy: ... More on github.com
🌐 github.com
1
October 7, 2020
🌐
CSS-Tricks
css-tricks.com › creating-vue-js-component-instances-programmatically
Creating Vue.js Component Instances Programmatically | CSS-Tricks
January 23, 2018 - I have been on a Vue.js project that required the ability to create components programmatically. By programmatically, I mean you create and insert the components completely from JavaScript, without writing anything in the template. This article aims to illustrate how different aspects of using components in a template, such as instantiation, props passing, slots, mounting, translates to JavaScript code.
Top answer
1 of 2
4

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.

2 of 2
2

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:

🌐
GitHub
github.com › vuejs › core › issues › 1802
Programatically create and mount a component instance · Issue #1802 · vuejs/core
August 6, 2020 - const app = Vue.createApp({}); const MyComponent = app.component('my-component', { template: '<div>Hello {{name}}</div>', props: ['name'] }); const myComponent = new MyComponent({ propsData: { name: 'Thomas' } }); myComponent.$mount('#my-component-mountpoint');
Author   mofux
🌐
Stack Overflow
stackoverflow.com › questions › 75757648 › vue2-programmatically-create-component-and-slots
vue.js - vue2 - Programmatically create component and slots - Stack Overflow
You can also create dynamic components this way iterating over component props with v-for. ... Vue.component('Test',{ name: 'Test', props: ['prop'], template: ` <div class="hello"> SLOTCONTENT: <slot name="name">default from template</slot><br> PROPS: {{$props}} </div>` }); new Vue({el:'#app'}) <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.7.14/vue.min.js"></script> <div id="app"> Component created with new Vue() <Test id="el1" prop="el1prop"> <template #name>el1 (from markup)</template> </Test> <br> <Test id="el2" prop="el2prop"> <template #name>el2 (from markup)</template> </Test> <br> <Test id="el3" prop="el3prop"> <template #name>el3 (from markup)</template> </Test> </div>
🌐
GitHub
github.com › vuejs › core › issues › 2331
Vue3 Creating Component Instances Programmatically · Issue #2331 · vuejs/core
October 7, 2020 - import Button from 'Button.vue' import Vue from 'vue' var ComponentClass = Vue.extend(Button) var instance = new ComponentClass() instance.$mount() // pass nothing this.$refs.container.appendChild(instance.$el) extend create instance. But in vue3 it's has been deleted. Where are another way? Like vue2 · 👍React with 👍4adamberecz, Calvin-2DWeb, anafro and arthabus ·
Author   art2limit
Find elsewhere
🌐
GitHub
github.com › vuejs › rfcs › discussions › 582
Improve rendering vue components programmatically · vuejs/rfcs · Discussion #582
Render and mount a vue component inside a specific dom element programmatically. Easly update its props and propely utilize vue's diffing algorithm to update the mounted component template.
Author   vuejs
🌐
Devshive
devshive.tech › link › bjuzubxle › creating-vuejs-component-instances-programmatically
Creating Vue.js Component Instances Programmatically | Devs' Hive
February 24, 2019 - ...it fails. We need a class. Or, in simple terms, a constructor function. The way to do that is to pass the component object to Vue.extend to create a subclass of the Vue constructor.
Top answer
1 of 4
12

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.

2 of 4
2

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');


🌐
YouTube
youtube.com › overseas media
Vue: Mount a component programmatically (4 lines of code) - YouTube
Jump to 5:05 for the actual code. This video will show you how to mount a component in Vue programmatically for whatever reason you wanna do that, i explain ...
Published   April 15, 2020
Views   674
🌐
MDN Web Docs
developer.mozilla.org › en-US › docs › Learn_web_development › Core › Frameworks_libraries › Vue_first_component
Creating our first Vue component - Learn web development | MDN
Create a <script></script> section below your template section. Inside the <script> tags, add a default exported object export default {}, which is your component object. ... We can now begin to add actual content to our ToDoItem. Vue templates are currently only allowed a single root element ...
🌐
Vue.js
vuejs.org › guide › essentials › component-basics
Components Basics | Vue.js
You can also use the is attribute to create regular HTML elements. When switching between multiple components with <component :is="...">, a component will be unmounted when it is switched away from. We can force the inactive components to stay "alive" with the built-in <KeepAlive> component. If you are writing your Vue templates directly in the DOM, Vue will have to retrieve the template string from the DOM.
🌐
Vue.js
v2.vuejs.org › v2 › guide › components
Components Basics — Vue.js
Upgrade to Vue 3 or learn more about | Vue 2 EOL. ... Join the Vue.js Community! ... Components are reusable Vue instances with a name: in this case, <button-counter>. We can use this component as a custom element inside a root Vue instance created with new Vue:
Top answer
1 of 3
23

Ok, so I looked into dynamic elements and managed to pull this together:

Vue.component('form-input', {
  template: '#form-input'
});

Vue.component('form-select', {
  template: '#form-select'
});

Vue.component('form-textarea', {
  template: '#form-textarea'
});

new Vue({
  el: '#app',
  data: {
    fields: [],
    count: 0
  },

  methods: {
    addFormElement: function(type) {
      this.fields.push({
        'type': type,
        id: this.count++
      });
    }
  }
})
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
<div id="app">
  <component v-for="field in fields" v-bind:is="field.type" :key="field.id"></component>

  <button type="button" v-on:click="addFormElement('form-input')">Add Textbox</button>
  <button type="button" v-on:click="addFormElement('form-select')">Add Select</button>
  <button type="button" v-on:click="addFormElement('form-textarea')">Add Textarea</button>
</div>

<script type="x-template" id="form-input">
  <div>
    <label>Text</label>
    <input type="text" />
  </div>
</script>

<script type="x-template" id="form-select">
  <div>
    <label>Select</label>
    <select>
      <option>Option 1</option>
      <option>Option 2</option>
    </select>
  </div>
</script>

<script type="x-template" id="form-textarea">
  <div>
    <label>Textarea</label>
    <textarea></textarea>
  </div>
</script>

So instead of creating a new form-input component for each item in the fields array, I'm creating a new component that is associated with the correct component via the type property of the fields

2 of 3
1

You can pass the field object as props of your form-input component and make the type dynamic:

Vue.component('form-input', {
  template: '#form-input',
  props: ['field']
})

new Vue({
  el: '#app',
  data: {
    fields: [],
    inputType: '',
    count: 0
  },
  methods: {
    addFormElement(val) {
      this.fields.push({type: val, placeholder: 'Textbox ' + (++this.count)});
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app">
  <h3>Add form element</h3>
  <select size="3" v-model='inputType' @click="addFormElement(inputType)">
    <option value="text">Text</option>
    <option value="checkbox">Checkbox</option>
    <option value="radio">Radio</option>
  </select>
  <p>
    <form-input v-for="field in fields" :field="field"></form-input>
  </p>
</div>

<template id="form-input">
  <div>
    <label>{{ field.type }}</label>
    <input :type="field.type" />
  </div>
</template>

🌐
Reddit
reddit.com › r/vuejs › vue3 - how to create component instances programmatically?
r/vuejs on Reddit: Vue3 - How to create component instances programmatically?
August 23, 2020 -

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?

🌐
Stack Overflow
stackoverflow.com › questions › 40933380 › vue-js-create-component-programmatically
Vue js create component programmatically
December 2, 2016 - I have a modal component that I want to be able to insert programmatically when I want. There is a way to do this with Vue? ... Vue.component('login', { methods: { openLoginModal() { // Create the component modal and pass the props } } });
🌐
Telerik
telerik.com › blogs › dynamic-components-vue-component
Dynamic Components with Vue's 'component'
November 30, 2020 - In this article we will explore Vue's <component>, <keep-alive> and how to create dynamically loaded components.