Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for running in shadow DOM #3891

Open
Reinmar opened this issue Nov 21, 2016 · 50 comments
Open

Support for running in shadow DOM #3891

Reinmar opened this issue Nov 21, 2016 · 50 comments
Labels
package:engine squad:core Issue to be handled by the Core team. support:2 An issue reported by a commercially licensed client. type:feature This issue reports a feature request (an idea for a new functionality or a missing option).

Comments

@Reinmar
Copy link
Member

Reinmar commented Nov 21, 2016

Apparently, shadow DOM has its own selection (like an iframe), so when running in a shadow root, the engine must use that selection.

Welcome to hell...


Add 👍 if you're interested in support for shadow DOM in CKEditor 5.

@Reinmar
Copy link
Member Author

Reinmar commented Nov 21, 2016

@Reinmar Reinmar changed the title Support for shadow DOM Support for running in shadow DOM Nov 21, 2016
@paales
Copy link

paales commented Nov 21, 2016

Haha, thanks for creating the issue! Welcome to the wonderful world of Custom Elements and Shadow Dom. Ps, should probably also work with Shady DOM.

  • At the moment it does properly work with Shady DOM.
  • At the moment custom CSS variables do not work with Shady DOM, but they do work Shadow DOM.
  • The errors at the moment don't seem too intrusive as the complete application seems to be working.

@Reinmar
Copy link
Member Author

Reinmar commented Nov 22, 2016

Hey, thanks for bringing this up. We always wanted to make a custom element for CKEditor (not a big deal itself) but we haven't yet worked on it for CKEditor 5 so we didn't notice that shadow DOM is a bigger problem. The fact that shadow DOM has its own selection will require some changes in the engine, but they should be possible to hide beneath the abstraction that we made.

I've just thought about one more thing – CKEditor instance is usually represented by two DOM structures – one which holds the editor itself and one which holds floating elements (e.g. balloon panels). If editor will be enclosed in a custom element and shadow root, how to create the other root which needs to be directly in the <body>? Can editor do this itself or should we require that the developer does something special (create another element for the "body root")?

I hope this isn't very stupid question, cause I haven't played with custom elements and shadow DOM myself :D.

@Comandeer
Copy link
Member

If you have a control over the custom element itself, there is no issue with getting its owner document, so you have full access to the body.

However I'm not sure if it's a good solution to request access to body when everything is encapsulated into custom element and/or Shadow DOM. Such component should be totally independent and self-contained (well, it's the main use case for the whole Web Components ecosystem…). The "true WC editor" should include toolbar as a part of the whole my-editor custom element, something like: https://jsfiddle.net/Comandeer/nfwc1sud/

@Reinmar
Copy link
Member Author

Reinmar commented Nov 22, 2016

However I'm not sure if it's a good solution to request access to body when everything is encapsulated into custom element and/or Shadow DOM. Such component should be totally independent and self-contained

Unfortunately, it's a must have that some elements are directly in body. Otherwise, if editor is used in an element with a fixed size and overflow:hidden, the balloons or modals (if we'll ever have any) might render partially invisible.

@fredck
Copy link
Contributor

fredck commented Nov 22, 2016

I was wondering if floating panels should not endup inside yet another custom element created on the fly for that purpose and positioned within body :?

But wait, why we need to access body? I have the impression that floating elements will be simply inside the custom element itself.

@Reinmar
Copy link
Member Author

Reinmar commented Nov 22, 2016

But wait, why we need to access body? I have the impression that floating elements will be simply inside the custom element itself.

See my comment above. They cannot be in the custom element holding the editor itself (which can be wherever in the DOM structure). They must be in a special custom element (or any element in fact) which is always directly in the <body>.

I was wondering if floating panels should not endup inside yet another custom element created on the fly for that purpose and positioned within body :?

That was my idea too. I just wonder whether it should be CKEditor creating that container or a developer. For the convenience, it'd be nice if the editor did that. But is it ok for developers?

@fredck
Copy link
Contributor

fredck commented Nov 22, 2016

which is always directly in the <body>.

You didn't answer why, though.

@Reinmar
Copy link
Member Author

Reinmar commented Nov 22, 2016

I did :P Because they won't be rendered if the editor is in an element which has overflow:hidden and fixed size (which happens). It's the same case as an editor created in an iframe – the UI of that editor must fit in that iframe, otherwise it will be invisible.

We had multiple bug reports about this in the past.

@fredck
Copy link
Contributor

fredck commented Nov 22, 2016

Ouch... those creative use cases :)

I just wonder whether it should be CKEditor creating that container or a developer. For the convenience, it'd be nice if the editor did that. But is it ok for developers?

I think they would be surprised if the editor would not do that. It would be almost transparent to them, anyway.

@Reinmar
Copy link
Member Author

Reinmar commented Nov 22, 2016

Or maybe I'm wrong... https://jsfiddle.net/pp7z788w/

Strange. Cause I'm pretty sure there were problems with that. Otherwise, why would CKE4 went this way? Maybe it was some old browser. We should check it.

@Reinmar
Copy link
Member Author

Reinmar commented Nov 22, 2016

OK, now it's bad: https://jsfiddle.net/pp7z788w/1/

@Comandeer
Copy link
Member

And now it's good again ;) https://jsfiddle.net/pp7z788w/2/

Maybe the use of position: fixed and positioning against visible viewport (not the whole page) could be a way to go?

@Reinmar
Copy link
Member Author

Reinmar commented Nov 22, 2016

Heh... let me guess. CKE4 was forced to put floating stuff to the body, because there was no position:fixed in IE6? :D

If there's no gotcha with the position:fixed, then perhaps it'll be fine.

BTW, @Comandeer, do you know the place in the CSS spec clarifying why position:fixed behaves differently that position:absolute in this case? :D

cc @oleq

@Comandeer
Copy link
Member

Comandeer commented Nov 22, 2016

BTW, @Comandeer, do you know the place in the CSS spec clarifying why position:fixed behaves differently that position:absolute in this case? :D

Of course:

Fixed positioning is similar to absolute positioning. The only difference is that for a fixed positioned box, the containing block is established by the viewport.

Heh... let me guess. CKE4 was forced to put floating stuff to the body, because there was no position:fixed in IE6? :D

Actually it's not that simple. Some mobile browsers had some issues too. But, according to Can I Use? it's safe now (unless we support also Opera Mini).

I'm not 100% sure that fixed will be always working fine, but IMO it seems like a good solution.

@Reinmar
Copy link
Member Author

Reinmar commented Nov 22, 2016

I'm not 100% sure that fixed will be always working fine, but IMO it seems like a good solution.

If we're able to easily get the position of some elements/caret relative to the true viewport (and I think that this is the default behaviour of most of the DOM methods), then using position:fixed seems to be the thing that would be the easiest to use.

BTW, there's another DOM structure which may cause issues – we need an <svg> element with icon sprite. Hopefully, it will work inside editor element just fine.

BTW2, I wonder how all that would look in case of an inline editor (with a floating toolbar) – like in this one here: http://sdk.ckeditor.com/samples/inline.html. For this case it's hard for me to imagine the custom element application, because you actually want to make an existing, normal element, an editor.

@Comandeer
Copy link
Member

For this case it's hard for me to imagine the custom element application, because you actually want to make an existing, normal element, an editor.

Look into my demo ;) That normal element could be wrapped into dgui-editor element and then automatically put into slot (light DOM of custom element – its content – is distributed to the slot inside Shadow DOM).

@oleq
Copy link
Member

oleq commented Nov 23, 2016

I'm not 100% sure that fixed will be always working fine, but IMO it seems like a good solution.

Maybe yes, maybe not. The thing is that if some element residing in a dedicated container in <body> (i.e. a balloon panel or toolbar) gets position:absolute, it preserves positioning as the web page scrolls because, in fact, it is anchored to the element which is being scrolled.

If we go with position:fixed, it will mean constant re–positioning when the web page scrolls because viewport is constant and to follow the content that panel/toolbar is attached to (a link, the caret, whatever), it must be re–positioned again, and again and again. So here's the performance issue.

Still, we may put up with performance issues and more complex implementation to maintain, but the real issue I see is Safari in iOS. I researched possibilities to develop a mobile experience in CKEditor5 and the very general conclusion was more or less: "when the software keyboard kicks in Safari in iOS, position:fixed stops working". I didn't check what would happen to the overflow in such situation but it's a really big issue anyway, isn't it?

@Reinmar
Copy link
Member Author

Reinmar commented Nov 23, 2016

If we go with position:fixed, it will mean constant re–positioning when the web page scrolls because viewport is constant and to follow the content that panel/toolbar is attached to (a link, the caret, whatever), it must be re–positioned again, and again and again. So here's the performance issue.

Great point. Doing anything in DOM on scroll is an antipattern AFAIK. We could, of course, debounce it and use CSS transitions for nicer effects but we'd be still doing something on scroll, so a static positioning feels better in this case.

@jay8t6
Copy link

jay8t6 commented Sep 29, 2017

+1

Is there a plan on getting ckeditor to run on shadow dom? We are using ckeditor in our polymer element, it works fine on shady, but not on shadow dom. It would be really great if we can get ckeditor to play nicely with shadow dom.

@Reinmar
Copy link
Member Author

Reinmar commented Sep 29, 2017

Not yet. We haven't researched it so neither we know how hard will it be nor have we seen much interest on that (I guess that this is because it's still a Blink-only feature or so at least Can I use says so).

Also, a thing which worries me is that there's a high probability that contentEditable will behave differently in different browsers' implementations of shadow DOM (once they get there). I'm afraid that for a looong time this would become an experimental feature – not really something that you can really rely on.

Anyway, the first things to figure out are:

  • How to make the engine use the right selection instance?
  • What differences are there between contentEditable's and other APIs' behaviour in shadow DOM and normal DOM? What else we'd need to change?
  • How to rewrite some of the floating/sticky UI components so they don't need to be injected directly into <body>? Or, if that turns out to not be feasible, how to make CKEditor work across shadow DOM boundary (which kinda seems like working with iframes again)?

Any help with these aspects might help speed up development of this feature.

@paales
Copy link

paales commented Sep 30, 2017

@Reinmar Just a quick mention. You've linked to the V0 spec, the actual spec to be implemented is the V1 spec: http://caniuse.com/#feat=shadowdomv1

I think a wysiwyg editor is the perfect example of a custom element that should be running in shadow DOM. Just drop in a <ck-editor/> in your html seems great. I can't answer al your questions, but in general the shadow dom API seems to be nice.

If you really want to, you can even create a custom element without shadow dom and do everything in the light (normal) DOM. That might solve some issues.

@chrisekelley
Copy link

@Reinmar To help illlustrate the differences between the different doms, I have created a testbed for hoisting ckeditor5 into the shadow dom (via polymer), shady dom, and normal dom here: https://github.com/chrisekelley/polymer-ckeditor5

@jay8t6
Copy link

jay8t6 commented Apr 9, 2018

Just an FYI, there was a PR on tinymce editor repo to add shadow dom support that was merged back in January:
tinymce/tinymce#561

@nazar-pc
Copy link

@jay8t6 it was closed back in January without merge. And will require serious rebase in order to be mergeable again, but there is literally no interest from upstream developers despite what they publicly say.

@Reinmar
Copy link
Member Author

Reinmar commented Apr 10, 2018

Thanks for the updates! Do you know how stable and consistent is contentEditable and Selection in shadow DOM and shadydom? My biggest worry now is that investing in researching how to work with shims will be a waste of time because natively things may work differently. Our experience is that proper support contentEditable and Selection are usually omitted in various tools (e.g. Selenium ;/).

What I'd focus on first is making sure it all works in Chrome and Firefox which support Shadow DOM natively. Does that sound reasonable?

@nazar-pc
Copy link

I've managed to get TinyMCE fully working under both WebComponents v0 polyfill and native implementation in Chromium back in 2015. Though, I've reported one or two issues in Chromium (which I believe are fixed already) and sent a few patches to polyfills to fix various edge cases (I have quite an experience fixing various tricky Shadow DOM-related issues over last few years).

Things have changed since then, there is v1 polyfill that have significantly reduced number of abstractions. Overall I think it should be in much better shape now. The only caveat might be Safari, I have no idea what its implementation of Shadow DOM looks like.

v1 of the spec is considered stable, so Safari, Chromium and Opera should all work fine. If they are not - definitely push upstream developers to fix their stuff. Firefox and Edge are only working with polyfills in stable versions, so at least for nearest half a year you'll need to be able to get it working under polyfills too. Shouldn't be a major issue though.

@jay8t6
Copy link

jay8t6 commented Apr 10, 2018

@nazar-pc bummer! I really thought it was merged. I am in real need for an editor that supports shadow DOM.

@Comandeer
Copy link
Member

Back in December, Safari had totally different implementation of Shadow DOM than Chrome – it lacked Selection on shadow root. Because of that experimental plugin for CKEditor 4 with Shadow DOM support worked only in Chrome. However I haven't raised any issue as I couldn't find any standard stating that selection should be exposed on shadow root. Selection API specification does not mention Shadow DOM at all and in fact it's the only place, where Selection is defined. What's more, there's still open issue about implementing selection for shadow roots (targeted for v2 of WC). There's also a proposal, which describes actual behavior of browsers.

It seems that there is no sense in implementing Shadow DOM in RTEs as long as there isn't even a stable standard to base implementation on.

@ywsang
Copy link
Contributor

ywsang commented Jul 20, 2020

@Reinmar Hi there! I’ve been working on creating a web component version of CKEditor5, which involves putting the editor inside of shadow DOM. I’ve made a couple changes to the source code that help increase the amount of support for running the editor in the shadow DOM. So far, these changes are related to the editor’s styles (so that the editor looks visually correct when placed inside shadow DOM) and the engine selection issue. I’d love to contribute these changes back to the repo, though they’re not complete fixes for supporting running the editor in shadow DOM (this issue). Would you be open to accepting incremental changes towards this goal that tackle more fine-grained issues?

cc: @justinfagnani

@yoyo837
Copy link

yoyo837 commented Apr 8, 2022

Can we consider this in 2022?

@ralfpatric
Copy link

Any idea if this will come in 2023? 🤔

@Witoso
Copy link
Member

Witoso commented Jun 30, 2023

@ralfpatric most likely not, we have not currently set it as a priority.

@mancristiana
Copy link

mancristiana commented Jul 14, 2023

I reproduced the issue we are facing when adding CKEditor in ShadowDOM
https://stackblitz.com/edit/lit-element-ckeditor5-xd7j6g?file=index.html,index.js,package.json

I would like to contribute to this issue. What would be the recommended way to setup this test case with ShadowDOM?

@Reinmar
Copy link
Member Author

Reinmar commented Jul 31, 2023

I don't want to be the party killer here but the problem with shadow DOM isn't (to our knowledge) really fixable at the moment. It's been a while since we investigated this and AFAICS we failed to share the details here, but all issues except one were rather straightforward to fix.

The one issue being: selection handling 😳🤬

There's currently no standardized API to access selection in a shadow root. If there were even different APIs, but somehow compatible, we could somehow resolve this ticket. But nope – it's 2023 and the state is as follows:

When researching this over a year ago we checked crazy hacks that we found. AFAIR, those were in line with: https://github.com/jsturgill/shadow-root-get-selection-polyfill. Unfortunately, our QA team found many instabilities of those hacks. I can share the results if someone's interested, but it really didn't look promising.

The thing is – all editor developers are struggling with this unless they are using an <iframe> to wrap the editable element. And while we could ship some shadow DOM support with those hacks, that'd be a false promise of a usable feature.

I pinged Firefox guys because I can't believe we'll see the spec for this in the next 3 years. If there will be no reaction, I think that we'll consider going with no hacks but also no Firefox support (or hacks to support Firefox, but without aiming at making it super stable). This is depressing but it may be the only choice.

@bnf
Copy link

bnf commented Sep 12, 2023

@Reinmar FYI codemirror uses document.getSelection() as fallback if getSelection is not available on the shadow root, see
https://github.com/codemirror/view/blob/6.18.1/src/dom.ts#L1-L12
Introduced with codemirror/view@77e4111
With this we are able to use codemirror within shadow root with working selections.

Note: Firefox does not support the newer spec that is concerned about cross shadow root selections – e.g. when you select multiple elements with multiple shadow roots – but for running an editor within one shadow root, the existing API (shadowRoot.getSelection() with fallback to document.getSelection() should suffice)

Would that be an option for you? With https://bugs.webkit.org/show_bug.cgi?id=163921 being fixed, one should be able to parse selections in the editor's shadow root for chrome, firefox and safari.

@2dareis2do
Copy link

2dareis2do commented Nov 22, 2023

With regards

There's currently no standardized API to access selection in a shadow root. If there were even different APIs, but somehow compatible, we could somehow resolve this ticket. But nope – it's 2023 and the state is as follows:

Is it possible to use some form of polyfill? Maybe something like this:

https://github.com/GoogleChromeLabs/shadow-selection-polyfill

Sorry i realise that others have already suggested this approach. Looks possible.

This is as far as I have got with ckeditor

https://stackblitz.com/edit/lit-element-ckeditor5-83vd6t?file=index.js

To do the same in tinymce

https://codepen.io/twodareis2do/pen/BaMxbYN

This is basically what I want to to. Notice how styles are encapsulated in the tiny-mce component. e.g. try adding bootstrap class such as btn btn-primary using the source editor and compare to button out side.

@Witoso
Copy link
Member

Witoso commented Nov 27, 2023

@2dareis2do, thanks for your suggestions! Tiny under the hood is still a wrapper on an iframe, that's why the issues mentioned in this thread are not relevant to them.

@jogibear9988
Copy link

As it looks with the new API from Safari, ShadowDom could now be supported.
At least for me it works in my Webcomponent Designer Application with this Code:
https://github.com/node-projects/web-component-designer/blob/master/packages/web-component-designer/src/elements/helper/SelectionHelper.ts

@Witoso
Copy link
Member

Witoso commented Mar 4, 2024

Yes, v17 or 17.1 introduced getComposedRanges as @Reinmar stated, most likely it stabilized a bit in the latest four versions. FF is the biggest blocker for us right now, but AFAICS they haven't replied to our ping 😮‍💨

@jogibear9988
Copy link

But FF works with the document API,

@hsinyi
Copy link

hsinyi commented Mar 4, 2024

FWIW, there are activities and patches in this Firefox ShadowDOM selection issue .

@jogibear9988
Copy link

In my designer (https://node-projects.github.io/web-component-designer-demo/index.html) TextEditing in ShadowDom works with the current Firefox Version using the document.getSelection API

@Witoso
Copy link
Member

Witoso commented Mar 5, 2024

I understand, and congrats on your project, but we would like to minimize the special handling around selection to a minimum. I will keep in mind to test the proposed solution, and it's also reassuring that ProseMirror handles it this way. But it will likely not happen before other projects related to installation (#15502).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
package:engine squad:core Issue to be handled by the Core team. support:2 An issue reported by a commercially licensed client. type:feature This issue reports a feature request (an idea for a new functionality or a missing option).
Projects
None yet
Development

No branches or pull requests