surveyjs / survey-library

Free JavaScript form builder library with integration for React, Angular, Vue, jQuery, and Knockout.
https://surveyjs.io/form-library
MIT License
4.12k stars 802 forks source link

Add support for ShadowDOM #5703

Closed skorupaw closed 6 months ago

skorupaw commented 1 year ago

MVCE

There are a lot of places in SurveyJS code where the document object is accessed directly. This code can be modified relatively easily and support for ShadowDOM can be added.

Are you requesting a feature, reporting a bug, or asking a question?

I'm requesting a feature

What is the current behavior?

document element is accessed directly along with some essential document methods preventing SurveyJS from being used inside ShadowDOM

What is the expected behavior?

document element won't be accessed directly, instead "envrionment" in which SurveyJS will be running can be controlled via settings this way ShadowDOM can be supported, without causing changes to current behavior.

Provide the example code and the tested page URL (if applicable)

Sample example from popup-view-model

How it is

if (!this.createdContainer) {
  const container: HTMLElement = document.createElement("div");
  this.container = this.createdContainer = container;
}

const mountContainer = document.body.querySelector(".sv-popup-mount");

if (mountContainer) {
  mountContainer.appendChild(this.container);
} else {
  document.body.appendChild(this.container);
}

How it can be

if (!this.createdContainer) {
  const container: HTMLElement = this.environment.createElement("div");
  this.container = this.createdContainer = container;
}
const mountContainer = "mountContainer" in this.environment
  ? this.environment.mountContainer
  : this.environment.body;

mountContainer.appendChild(this.container);

Specify your

Related issues:

Shadow dom Ranking question does not work in ShadowDOM

salimhb commented 1 year ago

The changes in #5715 break surveys under Rails https://turbo.hotwired.dev/

Turbo swaps the body Element when navigating to a new page. This results in settings.environment having outdated elements that are no longer in the DOM tree. A visible effect of this is that popup elements such as Dropdowns don't work anymore.

I'm using the package survey-knockout-ui and initializing the Survey in Stimulus controller.

My workaround is to reset the environment every time in the controller's connect() method

settings.environment.root = document
settings.environment.rootElement = document.body
settings.environment.popupMountContainer = document.body
settings.environment.svgMountContainer = document.head
settings.environment.stylesSheetsMountContainer = document.head

This might be an edge case only affecting my setup. Perhaps a general solution would be to add a check in settings.ts that makes sure the _rootElement is connected and otherwise falls back to document.body.

  get rootElement(): HTMLElement | ShadowRoot {
    return this._rootElement.isConnected ? this._rootElement : document.body;
  },
JaneSjs commented 11 months ago

+1

T15148 - Registered svg icons inside sv-icon-holder-global-container are not leaked inside shadow dom https://surveyjs.answerdesk.io/internal/ticket/details/T15148

tsv2013 commented 10 months ago

Closing since the work had been done, PR merged.

cworsley4 commented 6 months ago

My primary issue is that taliwind css mutates some base styles that conflict with SurvyeJS.

To solve this I was attempting to place SurveyJS in the Shadow DOM to separate tailwind and SurveyJS stylings. That worked with the new settings API described in the PR above. However, it seems that when drag&drop is used, it pulls the Shadow DOM root, and then get's the host property which is where it appends the dragged element. However, in that context the Survey JS CSS is not applied resulting in the element not appearing on screen.

|_ Host Element
   |_ Shadow DOM
   |_ Dragged Element 

IMO, the tree should look like this to pickup on the CSS...

|_ Host Element
   |_ Shadow DOM
      |_ Dragged Element <-- Indentation, styles applied.

What did I miss?

Edit: I'm working in React, incase that has implications, though I don't believe so.

dmitry-kurmanov commented 6 months ago

My primary issue is that taliwind css mutates some base styles that conflict with SurvyeJS.

To solve this I was attempting to place SurveyJS in the Shadow DOM to separate tailwind and SurveyJS stylings. That worked with the new settings API described in the PR above. However, it seems that when drag&drop is used, it pulls the Shadow DOM root, and then get's the host property which is where it appends the dragged element. However, in that context the Survey JS CSS is not applied resulting in the element not appearing on screen.

|_ Host Element
   |_ Shadow DOM
   |_ Dragged Element 

IMO, the tree should look like this to pickup on the CSS...

|_ Host Element
   |_ Shadow DOM
      |_ Dragged Element <-- Indentation, styles applied.

What did I miss?

Edit: I'm working in React, incase that has implications, though I don't believe so.

Thanks for the reporting! I'll check it as soon as possible.

dmitry-kurmanov commented 6 months ago

@cworsley4 I created a separate issue (https://github.com/surveyjs/survey-library/issues/7965) for the problem