Closed ivanov-wai closed 3 years ago
There are no plans currently to support web components
See also #4075, #5054, #6203
@KaelWD The issue is not about web components. It is about handling the case when the vuetify app is rendered inside shadow DOM
Yeah sorry I didn't really look to closely because it seemed very similar to other issues at first. The closest one is probably #6203 as we are using document
directly and not accounting for shadow DOM.
A solution to this would be for use to replace document
with getRootNode
and a polyfill for IE. The second suggestion wouldn't for for the reason stated in #6203.
Followed the web of issues and feel this is the right place to jump in. Super interested in this and willing to have our team dedicate some time to it, but this would be our first venture in to this codebase (though we've contributed to plenty of other OSS in various minor capacities) and might need a little support getting started.
Took a super precursory grep document
and realized it doesn't seem like a clean cut case across the entire library, even though there's less than a hundred references (tests included). @KaelWD could you or others help craft a strategy on how best to tackle this? Assuming a well placed getRootNode
on the lib or config would get us far, but would love even just a 30k foot view of how best to target it.
Took a pretty deep dive today and it looks manageable. Excluding the specs/tests, I had less than 90 refs to document
and many of which are not what we need to target. I still don't fully grok the "why" on some of these calls, and can't help thinking that while we're in here trying to do this it might make sense to look at a more wholistic strategy for this kind of thing. Thoughts?
Any progress on this? This would be a pretty useful feature.
@TheInvoker Been wrapped up with a big release, but I'm actually hoping to take a stab at it on Sunday. Happy to collaborate on it if you'd like
In the meantime, what you can do is:
const vuetify = new Vuetify(options)
// @hack: Make sure we don't re-use the page's current style element
vuetify.framework.theme.checkOrCreateStyleElement = function () {
if (!this.styleEl) this.genStyleElement()
return Boolean(this.styleEl)
}
const app = new Vue({ ..., vuetify })
const shadowHost = document.createElement('div')
// Add shadow host wherever you want in the DOM
document.body.appendChild(shadowHost)
const shadowRoot = shadowHost.attachShadow({ mode: 'closed' })
// Move vuetify theme style element from document.head into shadowDom
const { styleEl } = vue.$vuetify.theme
styleEl.remove()
shadowRoot.appendChild(styleEl)
// Monkey patch querySelector to properly find root element
const { querySelector } = document
document.querySelector = function (selector) {
if (selector === '[data-app]') return shadowRoot
return querySelector.call(this, selector)
}
app.$mount(shadowRoot.appendChild(document.createElement('div')))
This will break if there is more than one instance of Vuetify running on the page.
There are other consideration than only the use of document
. For example, the use of rem
css units will prevent overriding the font-size of elements inside the shadow dom.
I don't expect the Vuetify team to implement these changes in Vuetify 2.x (although it would be nice). But you guys should consider this when writing Vuetify 3. IMO, a proper framework should not assume that it is the only think running on the page and allow to be scoped to a particular DOM element.
@matthieusieben I don't get why your workaround breaks with more than one Shadow DOM? Could you explain?
Do you mean more than one Shadow DOM that uses Vuetify? Even then the scoping in the #data-app seems sufficient (considering of course that the referenced id is specific to each instance). I'm very new to shadow DOM though so there is probably something I don't get.
@jggc updated my comment: It will break Vuetify if more than one instance of Vuetify runs on the page (which, in my case, happened to run from "inside" a shadow DOM)
PR https://github.com/vuetifyjs/vuetify/pull/13053 fixes the "Cannot focus for text fields" issue.
Any progress on this?
@matthieusieben did you guys ended using some kind of a patch to have multiple vuetify instances (in different shadow-doms) on the same page? I guess patching querySelector is the problematic part, right?
This is fixed for text fields but not menus. Menus can use attach
as a workaround.
@guyschlider in my case, we are running a full Vue instance inside a chrome extension. This is quite convenient because web extension have a local "copy" of the DOM. This means that the monkey patching of document.querySelector
only affects the JS of the extension itself.
There are more problematic parts than the document.querySelector
though. For example; Vuetify's theme engine will generate one style sheet per vuetify instance. And the generated CSS is not "namespaced" to the v-app
. So running multiplie themes will be an issue as well.
Note that with the attachedRoot
too introduced in https://github.com/vuetifyjs/vuetify/commit/dc19b82e2b9178ddf553b42a981208d6f2d811ac#diff-5bbdbd8c956db1e85f2f5845e151d3d1bd46e2bda71994cecfc579bec5c3de71R1-R24 , it should be easy to patch some of the other problematic parts of the code (including the attach
issue).
@KaelWD
Using Vuetify@2.4.6. A standalone Text-Field focuses as expected within the shadow DOM.
The Autocomplete (internal Text-Field) within a shadow DOM fails to focus or display the menu when focused. Auto-focus initially applies focus as expected.
Test implementation: https://codepen.io/MalachiMart/pen/PobVEdo
Has anyone else experienced this since version 2.4.5?
@Malachi-M Autocomplete does not work. Menu with attach workaround appears but closes after interaction with date picker inside it (despite :close-on-content-click="false"
)
I don't know if this helps but I managed to find a way to move all of the Vuetify styles from <head>
to shadow DOM.
Add style-loader to webpack config, with these options:
{
test: /\.(sass|less|css|scss)$/,
use: [
...
{ loader: "style-loader", options: { attributes: { class: "some-class" }, injectType: 'singletonStyleTag'} },
...
],
},
Then, in your main.js file or whatever it's called, use javascript to move the styles to shadow DOM:
import Vue from "vue";
import Vuetify from "vuetify/lib";
vuetify.framework.theme.checkOrCreateStyleElement = function () {
if (!this.styleEl) this.genStyleElement()
return Boolean(this.styleEl)
}
const app = new Vue({
Vuetify,
...
});
const shadowHost = document.querySelector('#shadowHost')
const shadowRoot = shadowHost.attachShadow({ mode: 'open' })
const { styleEl } = app.$vuetify.theme
styleEl.remove()
shadowRoot.appendChild(styleEl)
let styles = document.querySelectorAll('style.some-class')
shadowRoot.appendChild(styles[0])
app.$mount(shadowRoot.appendChild(document.createElement('div')))
Some parts from the code above are taken from @matthieusieben's comment.
Has the issue of not recognizing vuetify options inside of the web component been solved in the new version of Vuetify 3?, I've implemented the vuetify for a web component created by Vue3, but my options don't work correctly for web component. This is the link to my project:vue-web-component
Versions and Environment
Vuetify: 1.5.14 Vue: 2.6.10 Browsers: Google Chrome OS: Linux x86_64
Steps to reproduce
VApp
Expected Behavior
Clicking on the text field should show that the text field is focused The select list should work even without
attach
propertyActual Behavior
The text field does not react on clicks or activating via tab The select list does not open without
attach
propertyReproduction Link
https://codepen.io/anon/pen/rEjXRj
Other comments
Possible culprit:
document.activeElement
inside ofonFocus
inVTextField
does not work in shadow domdocument.querySelector
does not work in shadow domPossible solutions:
getRootNode
(might require polyfill on Edge and IE11)VApp
and usequerySelector
directly on theVApp
elementI could not find any workarounds that vuetify can offer for this issue at this moment.