vuejs / vue-web-component-wrapper

(Vue 2 only) Wrap a Vue component as a web component / custom element.
1.05k stars 100 forks source link

Vuetify compatibility #128

Open DallyBoodil opened 1 year ago

DallyBoodil commented 1 year ago

As with vue-custom-element, I'm having the same problem with getting Vuetify to working when the custom element is using shadowDOM.

vue-custom-element works fine when it's not using shadowDOM but it's not a bulletproof solution due to CSS conflicts when importing the web component onto 3rd party websites.

The error I get is the following:

[Vuetify] Unable to locate target [data-app]

found in

---> <VDialog>
       <Payment> at src/views/Payment.vue
         <VApp>
           <App> at src/App.vue
             <Root>

Has anyone encountered the same issue and managed to get Vuetify to work with shadowDOM?

alfreema commented 1 year ago

For that particular problem, add a <div data-app/> element to your HTML source file that is using your web component.

eytienne commented 1 year ago

@alfreema Could you further develop what to do?

I have this in my HTML:

<my-component/>

This in my typescript entrypoint:

const customLoginModal = wrap(Vue, {
        vuetify: new Vuetify(vuetifyConfig()),
        template: `<MyComponent/>`,

Then MyComponent.vue:

<template>
    <v-app id="my-component-app" v-if="dialog">
        <v-dialog v-model="dialog" fullscreen
...
alfreema commented 1 year ago

I don't think v-dialog works well inside a web component, but if you want them to work at all you have to put:

<div data-app/>
<my-component/>

in your HTML. Vuetify requires a div with data-app attached to it. See this answer for another example of the issue: https://stackoverflow.com/a/60990132/2957186

I suppose you could create it dynamically in javascript too, but I didn't try it. You'd do something like ...

var appDiv = document.createElement('div')
appDiv.setAttribute('data-app')
document.body.appendChild(appDiv)

but I went a different direction.

I gave up on using v-dialog as it introduced a host of issues and I found that using a standard HTML <dialog> worked quite well in it's place. I styled the <dialog> like this:

<style scoped>
  /* Make the dialog "full screen"-ish, and center it vertically and horizontally */
  #dialog {
    height: 100vh;
    width: 100vh;
    border-radius: 5px;
    border: none;
    margin: auto;
  }
  /* Make the background behind the dialog transparent but dark */
  #dialog::backdrop {
      background-color: rgb(4, 4, 16);
      opacity: 0.6;
    }  
</style>

v-dialog is one of the only Vuetify components I really tussled with other than perhaps v-autocomplete. So far the rest of the components have worked quite well inside my web component.