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...
https://www.w3.org/TR/shadow-dom/#ranges-and-selections
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.
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.
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/
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.
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.
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?
which is always directly in the
<body>
.
You didn't answer why, though.
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.
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.
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.
OK, now it's bad: https://jsfiddle.net/pp7z788w/1/
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?
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
BTW, @Comandeer, do you know the place in the CSS spec clarifying why position:fixed behaves differently that position:absolute in this case? :D
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.
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.
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).
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?
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.
+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.
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:
<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.
@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.
@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
Just an FYI, there was a PR on tinymce editor repo to add shadow dom support that was merged back in January:
https://github.com/tinymce/tinymce/pull/561
@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.
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?
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.
@nazar-pc bummer! I really thought it was merged. I am in real need for an editor that supports shadow DOM.
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.
CKEditor in Shadow DOM would be awesome. Until then, the trick is with using CKEditor with web components is to never put CKEditor in the shadow DOM, instead putting it in a slot so that the CKEditor instance is "in" the web component yet part of the parent document.
I'm woefully unfamiliar w/ ckeditor's codebase; but, FWIW, here's a little routine we've used in a custom element that uses shadow dom containing a contenteditable... this works under native shadow dom and polyfilled shady dom.
class MyContentEditable extends HTMLElement {
_getSelection() {
return this._findSelectionProvider().getSelection();
}
/**
* return the node that supports "getSelection"
* https://developer.mozilla.org/en-US/docs/Web/API/DocumentOrShadowRoot/getSelection
*/
_findSeletionProvider() {
if (super.getSelection) {
return this;
}
var parent = this.target;
let types = [
Node.DOCUMENT_TYPE_NODE,
Node.DOCUMENT_FRAGMENT_NODE
];
while (parent) {
if (types.indexOf(parent.nodeType) > -1 && parent.getSelection) {
return parent;
}
parent = parent.parentNode || parent.host;
//parent maybe a shadowRoot or a slot
}
}
}
We'd love to be able to use CKEditor in the shadows!
CKEditor in Shadow DOM would be awesome. Until then, the trick is with using CKEditor with web components is to never put CKEditor in the shadow DOM, instead putting it in a slot so that the CKEditor instance is "in" the web component yet part of the parent document.
@rjsteinert it would be great to see an example of this in action!
Here's an example of where it works and doesn't, maybe fork this as a start and get a simple setup going to help everyone? https://stackblitz.com/edit/lit-element-ckeditor5
@aadamsx That's a nice and simple example you've provided. Here the demo of the tangy-form-editor element that uses CKEditor4 FWIW https://tangy-form-editor.glitch.me/
FYI – I created a master ticker for componentizing CKEditor 5: https://github.com/ckeditor/ckeditor5/issues/1483.
Also, we seem to have a solution for the body collection issue discussed at the beginning of this thread – you can read more in https://github.com/ckeditor/ckeditor5/issues/1478.
@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
Most helpful comment
@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