What is the correct way to register and utilize props in a newly created Vue custom element?

I have started using the new defineCustomElement feature in Vue version 3.2.

Here is an example code snippet from main.js:

    import { defineCustomElement } from './defineCustomElementWithStyles'
    import App from './App.ce.vue'
    import store from './store'
    import router from './router'
    
    customElements.define(
      'app-root',
      defineCustomElement(App, {
        plugins: [store, router],
      })
    )

In the implementation file defineCustomElementWithStyles.js:

import { defineCustomElement as VueDefineCustomElement, h, createApp, getCurrentInstance } from 'vue'

const getNearestElementParent = (el) => {
  while (el?.nodeType !== 1 /* ELEMENT */) {
    el = el.parentElement
  }
  return el
}

export const defineCustomElement = (component, { plugins = [] }) =>
  VueDefineCustomElement({
    render: () => h(component),
    setup() {
      const app = createApp()

      // install plugins
      plugins.forEach(app.use)

      app.mixin({
        mounted() {
          const insertStyles = (styles) => {
            if (styles?.length) {
              this.__style = document.createElement('style')
              this.__style.innerText = styles.join().replace(/\n/g, '')
              getNearestElementParent(this.$el).prepend(this.__style)
            }
          }

          // load own styles
          insertStyles(this.$?.type.styles)

          // load styles of child components
          if (this.$options.components) {
            for (const comp of Object.values(this.$options.components)) {
              insertStyles(comp.styles)
            }
          }
        },
        unmounted() {
          this.__style?.remove()
        },
      })

      const inst = getCurrentInstance()
      Object.assign(inst.appContext, app._context)
      Object.assign(inst.provides, app._context.provides)
    },
  })

In the component file App.ce.vue, I register and use a prop:

<template>
  <div id="app">
    <p>{{ title }}</p>
    <nav>
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link>
    </nav>
    <main>
      <router-view />
    </main>
  </div>
</template>
<script>
export default {
  name: 'App',
  props: {
    title: String,
  },
}
</script>

In the index.html where I set the value for the prop title:

<app-root title="hello"></app-root>

When running, I encountered an error message:

Uncaught TypeError: Cannot read properties of undefined (reading 'title')

You can find the full demo project here

Answer №1

When the App component is enclosed within defineCustomElementWithStyle, it's essential to transmit the wrapper's props to the App using setup().

  1. Replicate the component's props into the wrapper's props:

  2. Relocate the wrapper's render property into a return statement from setup().

  3. Provide the props argument of setup() while rendering the App (h() takes props as its second argument).

export const defineCustomElement = (component, { plugins = [] }) =>
  VueDefineCustomElement({
    props: component.props, 🛠️
    // render: () => h(component), 🚀
    setup(props 🪄) {
      ⋮
      return () => h(component, props 🪄)
    }
  })

live demo

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Incorporating Keyboard Features into Buttons

How can I toggle the page selectors in #pageList using a keyboard shortcut instead of clicking on the .togglePL button? I've tried looking up solutions online and asking questions here, but haven't found a working solution yet. Below is the code ...

Is it possible to store CSS and JS files within an Android app that utilizes a webview, similar to Phonegap

Looking to store CSS and JS files for an Android app that utilizes a webview. Want to avoid repeated server requests by storing the files locally on the phone, similar to how PhoneGap operates. Are there any resources or documentation available to help a ...

Capturing user-selected option from dropdown menu using npm

I am a beginner when it comes to node.js and async programming. My current project involves creating a program that shuffles a Spotify playlist. I have managed to store the user's playlists in an array for easier access. My goal is to present this ar ...

How to Extract a Link from JSON Data in React Native

My JSON data is formatted like this: orderData:"<p>Key VVV: 6326233</p> <p>Download link <a title=\"Movie\" href=\"https://play.google.com/store/movies/details/The_Angry_Birds_Movie_2?id=O_RbjOHHpIs&hl=en\" t ...

"Enhance User Experience with Multilevel Dropdowns in Bootstrap 4 - Submenus Aligned to the Top

I recently embarked on a project that involved using Bootstrap 4.4, The project is an eCommerce grocery store with departments comprising categories and subcategories. The main menu became very lengthy when using the default code, so I encountered some al ...

Tips for creating an HTML page with the dimensions of an A4 paper sheet?

My goal is to display the HTML page in a browser while containing the content within the dimensions of an A4 size page. Additionally, when printed, the HTML page should be formatted to fit onto A4-sized paper pages. <div classNa ...

Implementing the <p></p> tag within a loop practice session

Hello, I am currently stuck on a looping exercise and I could use some assistance. I need to display each iteration of the loop inside a < p > </ p > tag Looping away Looping away Looping away Looping away Looping away Below i ...

Verifying the functionality of a custom directive in Angular 2 (Ionic 2) through unit

In my ionic application, I developed a custom directive specifically for text masking, aimed at formatting phone numbers within input fields. The core functionality of this directive revolves around utilizing ngControl to facilitate the retrieval and assig ...

AngularJS: Issues with retrieving response headers following a $resource $save operation

When I run the $save function, which triggers my angularJS $resource to send a POST request to my API, everything seems to be working fine. I can successfully debug into the success callback handler and confirm that the object is created in my API. myObj. ...

I'm looking for the documentation for the latest version of Footable's Events. Can you point me

Does anyone know where to find information on the events that are fired for Footable and how to handle them? I checked the documentation at , but it doesn't provide much detail on events. If you have any resources or suggestions, please let me know! ...

Is your Vue.js chart malfunctioning?

I have been experimenting with chart.js and vue.js. The component I created is called MessageGraph, and it is structured like this (with data extracted from the documentation): <template> <canvas id="myChart" width="400" height="400">< ...

A guide to testing the mui Modal onClose method

When using material UI (mui), the Modal component includes an onClose property, which triggers a callback when the component requests to be closed. This allows users to close the modal by clicking outside of its area. <Modal open={open} onCl ...

Get the HTML source code for a form that has been created using AngularJS

Can AngularJS be used to download a portion of code generated by a form? Insert the following code snippet: http://jsbin.com/nufixiwali/edit?html,js,output I am looking to generate an .html file that only includes the code generated after the html tag. ...

Exploring the connections between data in Laravel and Vue to provide insightful displays

I am currently facing an issue with displaying data from a many-to-many relationship in my Vue component. After fetching user data from a REST API, I store it in an object like this: users: {}, //... axios.get("api/user").then(({data}) => (this.users ...

Tips for accessing nested array data using jQuery DataTables

Here is the JSON data I am working with: { "00100": { "claim_id": "21", "reference_no": "00100", "distributor_name": "Standard Match", "group_name": "A", "month": "Jun2017", "grand_total": "268.532", "details": [ { ...

JavaScript effect to make a div with a YouTube video fade in and out

I have limited knowledge of javascript, but I am curious if this idea can be achieved: I want to make the videos on my webpage invisible initially. When a user clicks on one of my links, I want a YouTube embed to fade in and start playing. Then, when the ...

What method sits snugly between prepend() and append()?

Just a quick question I have. I am attempting to align an element with my target. Usually, we use prepend (before the target) and append (after the target). Is there something similar that allows us to position that element directly on top of what we are ...

The dynamic data is not displaying on the Chart bundle JavaScript

I am currently utilizing chart bundle js for my project. While everything appears to be functioning properly on alter show, I am encountering an issue with the map display – nothing is showing up as intended. If anyone has a solution to resolve this iss ...

Error: Unable to iterate through users due to a non-function error while attempting to retrieve the firestore document

I encountered an issue with my code, receiving the error message: TypeError: users.map is not a function. Can anyone help me identify what might be wrong? const [users, setUsers] = useState([]); const getData = async () => { try { const use ...

How can aframe be integrated and utilized in Vue applications?

Trying to integrate aframe with vue-cli has been a challenge for me. I've experimented with adding aframe directly in the index.html file, as well as importing it in my top level main.js file, but I haven't had any success in getting Vue to recog ...