quasar: The global node for the q-menu, q-select, etc does not work well inside native web components

Describe the bug Sometimes there is a need to isolate the styles and code inside a native web component. In the 3.2 release, Vuejs delivers first class integration with the native web components. I have a need to use some elements (q-select) of Quasar inside one of those web components.

Everything is working very well, except the dropdowns, which are placed OUTSIDE the shadow dom of the component and thus the isolated styles of Quasar are not available there.

Codepen/jsFiddle/Codesandbox (required) https://l9iee.csb.app/ (click on the q-select)

To Reproduce

  1. Insert any quasar element that uses a popup inside a shadow dom
  2. Scope the quasar styles only to that component
  3. See that the quasar element is property styles
  4. See that the popup of that element does not have style

Expected behavior The popup should have styles as well

Platform (please complete the following information): Quasar Version: 2.0.4 on:

Quasar mode:

  • [x ] SPA
  • SSR
  • PWA
  • Electron
  • Cordova
  • Capacitor
  • BEX

Tested on:

  • [ x] SPA
  • SSR
  • PWA
  • Electron
  • Cordova
  • Capacitor
  • BEX

Additional context The problem is here https://github.com/quasarframework/quasar/blob/78df1f4939936fdbf591d90addf950a8f42e665b/ui/src/utils/private/global-nodes.js#L6

Inside a shadow dom, document.body should not be used

About this issue

  • Original URL
  • State: open
  • Created 3 years ago
  • Reactions: 4
  • Comments: 15 (1 by maintainers)

Most upvoted comments

I’m hitting this as an issue too.

I’m using Quasar as a Vite plugin since I want to package it as an app that can be displayed into a variety of existing web pages (with their own stylesheets that can’t be messed with).

So far, my process to deal with the styling issues are:

  1. Set Vite’s build mode to library and output all the CSS to file and then injecting a <link> to the css into the Shadow DOM.
  2. Using rollup-plugin-search-and-replace, swap out :root for :host to get the CSS variables working
  3. Run a MutationObserver to match the document.body classes with the root element in the ShadowDOM.

My one remaining problem is the teleported overlay elements. Which would be solved by being allowed to pass an override for using document.body as the root element.

I know there may be some display issues with suboptimal z-indexing, but right now, it just doesn’t work… which is surely worse.

I understand what you mean, it cannot be done reliably for native component users - that is true. Sure, there may be issues with the overflow and z-index - for those that are using it inside the native web components, but that is usually easily fixable and much better then it is now when the popups are not working at all.

I have made a few changes in quasar to make it work: If the element that requires the popup is inside the shadow dom, then place the popup node in the topmost position in the shadow dom, otherwise, use document.body as usually.

So there is no possible degradation for common users, it would work as it is now, just extra handling for this edge case.

Hope you reconsider, if not, no worries and thanks for your time!

@pdanpdan generally I see 3 main problems:

  1. Regarding elements like q-select, q-menu and q-dialog - it would be good that you can provide property “wrapper” to those elements so you can override default body selector.

  2. For global styles attached to body - you can create scss mixin so if you are using Quasar inside web component then you can use this mixin on the web component’s root element.

  3. Other problem is that Quasar append some classes to body element - e.g. “desktop” - it should be possible to pass base page selector(default body) while you init Quasar.

Apparently not.

Giving us a completely opt-in option to overwrite default behaviour is apparently unworkable because it would only work 95% of the time as opposed to 0% of the time.

Sorry, I somehow missed the link on the first post. But I still cannot see how this might work for the whole framework - because there are lots of things that depend on the html or body elements (classes mainly). I’ll reopen - maybe someone has an idea.

Hmm, dialogs also work 😄

@pdanpdan Solution suggested by @chetzof would be very helpful also for me because I have the same problem. It won’t break anything and just give possibility to specify web component as parent element instead of body 👍

I realise it is a narrow use case, but hopefully native components would start getting traction soon!