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
🌐
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.
🌐
Reddit
reddit.com › r/vuejs › creating components programmatically?
r/vuejs on Reddit: Creating components programmatically?
November 4, 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.

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:

🌐
Vue.js
forum.vuejs.org › t › add-component-to-dom-programatically › 7308
Build software better, together
March 1, 2017 - Date created · Top: Past day · Top: Past week · Top: Past month · Top: Past year · Top: All · Label · Filter · Loading · There was an error while loading. Please reload this page. Use alt + click/return to exclude labels. Filter: Open · Open · Closed · Locked · Unlocked · Answered · Unanswered · Verified · All · Loading · There was an error while loading. Please reload this page. Community guidelines · vuejs.org ·
🌐
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?

🌐
GitHub
github.com › vuejs › core › issues › 1802
Programatically create and mount a component instance · Issue #1802 · vuejs/core
June 5, 2020 - 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 MyComponent = Vue.component('my-component...
Author   mofux
Find elsewhere
🌐
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.
🌐
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 ...
🌐
Javascriptkicks
javascriptkicks.com › stories › 227972 › creating-vue-js-component-instances-programmatically
Creating Vue.js Component Instances Programmatically | JavaScriptKicks
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 ...
🌐
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.
Author   art2limit
🌐
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.
🌐
Medium
papereyra.medium.com › dynamically-loading-vue-3-components-a-composable-approach-d17a25e21fd5
Dynamically Loading Vue 3 Components: A Composable Approach | by Pamela Pereyra | Medium
December 20, 2023 - If there is no existing Vue app instance (app is null), it creates a new app instance using createApp and mounts the ConfirmDialog component to a dynamically created container element in the document body.
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');


🌐
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
🌐
DevPress
devpress.csdn.net › vue › 63174a4c237eb178e9dfbcdb.html
How to programmatically create a component instance in Vue 3?_javascript_Vue小助理-Vue
I have a Vue 2 pattern I was using for a common scenario: programmatically creating an instance to open a Modal/Dialog/Lightbox on dynamic content outside of a template. ... // DialogService.js export default { alert(text) { const DialogClass = Vue.extend(DialogComponentDef); let dialog = new DialogClass({ propsData: { text } }); dialog.$on('close', () => { dialog.$destroy(); dialog.$el.remove(); dialog = null; }); // mount the dynamic dialog component in the page const mountEl = document.createElement('div'); document.body.appendChild(mountEl); dialog.$mount(mountEl); }, };
🌐
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 } } });
🌐
GitHub
github.com › orgs › vuejs › discussions › 9330
Best method for rendering & controlling vue components programmatically · vuejs · Discussion #9330
September 12, 2024 - All global app plugins & providers are available for the rendered component. There is only one vue app instance create (the app instance is used to render the component)