How to stop extensions/add ons like grammarly on contenteditable editors
Solution 1
To disable Grammarly, you can add attributes on the <textarea>
element. The attributes keep changing, but you can add all of them to be safe.
data-gramm="false"
data-gramm_editor="false"
data-enable-grammarly="false"
Solution 2
So for Grammarly in particular, if you are patient/persistent you can submit a ticket and they will disable their plugin on your site. They won't fix the actual problem, they still inject almost 4MB of extra payload into your editor, I still see the problem when using their plugin on our Dev and QA sites.
I took the approach of Detecting / Alerting Users / Disabling the page. The message was slightly different for Firefox but to keep the sample below brief I stripped out the FF variables and the logging of the offending user.
/* vars intentionally over complicated to make detection more difficult */
//Chrome Message: gc;
var r = /\{0\}/g;
var gc = "PHN0eWxlPg0KCS5pY29uIHsNCgkJLXdlYmtpdC11c2VyLXNlbGVjdDogbm9uZTsNCgkJZGlzcGxheTogaW5saW5lLWJsb2NrOw0KCX0NCgkuaWNvbiB7DQoJCWJhY2tncm91bmQtcmVwZWF0OiBuby1yZXBlYXQ7DQoJCWJhY2tncm91bmQtc2l6ZTogMTAwJTsNCgkJaGVpZ2h0OiA3MnB4Ow0KCQltYXJnaW46IDAgMCA0MHB4Ow0KCQl3aWR0aDogNzJweDsNCgl9DQoJLmljb24tZ2VuZXJpYyB7DQoJCWJhY2tncm91bmQtaW1hZ2U6IHVybCgiZGF0YTppbWFnZS9wbmc7YmFzZTY0LGlWQk9SdzBLR2dvQUFBQU5TVWhFVWdBQUFKQUFBQUNRQVFNQUFBRGRpSEQ3QUFBQUJsQk1WRVVBQUFCVFUxT29hU2YvQUFBQUFYUlNUbE1BUU9iWVpnQUFBRkpKUkVGVWVGN3QwY0VOZ0RBTVE5RndZZ3hHNldqcGFJekNDQXhReFZnZ0Z1RGlDdmxMT2VSZEhSOXl6am5jSFZvcTNucHUrd1FVclV1Skh5bFNUbUJhZXNwSnlKUW9PYlVleXhEUWIzYkVtNUF1ODFjMHBTQ0Q4SFlBQUFBQVNVVk9SSzVDWUlJPSIpOw0KCX0NCgkuaW50ZXJzdGl0aWFsLXdyYXBwZXIgew0KCQlib3gtc2l6aW5nOiBib3JkZXItYm94Ow0KCQlmb250LXNpemU6IDFlbTsNCgkJbGluZS1oZWlnaHQ6IDEuNmVtOw0KCQltYXJnaW46IDEwMHB4IGF1dG8gMDsNCgkJbWF4LXdpZHRoOiA2MDBweDsNCgkJd2lkdGg6IDEwMCU7DQoJfQ0KCS5ibHVlLWJ1dHRvbiB7DQoJCS13ZWJraXQtdXNlci1zZWxlY3Q6IG5vbmU7DQoJCWJhY2tncm91bmQ6IHJnYig2NiwgMTMzLCAyNDQpOw0KCQlib3JkZXI6IDA7DQoJCWJvcmRlci1yYWRpdXM6IDJweDsNCgkJYm94LXNpemluZzogYm9yZGVyLWJveDsNCgkJY29sb3I6ICNmZmY7DQoJCWN1cnNvcjogcG9pbnRlcjsNCgkJZmxvYXQ6IHJpZ2h0Ow0KCQlmb250LXNpemU6IC44NzVlbTsNCgkJbWFyZ2luOiAwOw0KCQlwYWRkaW5nOiAxMHB4IDI0cHg7DQoJCXRyYW5zaXRpb246IGJveC1zaGFkb3cgMjAwbXMgY3ViaWMtYmV6aWVyKDAuNCwgMCwgMC4yLCAxKTsNCgl9DQo8L3N0eWxlPg0KPGJvZHkgaWQ9InQiIGNsYXNzPSJuZXRlcnJvciIgc3R5bGU9ImZvbnQtZmFtaWx5OiAnU2Vnb2UgVUknLCBUYWhvbWEsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogNzUlO2JhY2tncm91bmQtY29sb3I6ICNmN2Y3Zjc7IGNvbG9yOiAjNjQ2NDY0OyI+DQo8ZGl2IGlkPSJtYWluLWZyYW1lLWVycm9yIiBjbGFzcz0iaW50ZXJzdGl0aWFsLXdyYXBwZXIiIGpzdGNhY2hlPSIwIj4NCiAgICA8ZGl2IGlkPSJtYWluLWNvbnRlbnQiIGpzdGNhY2hlPSIwIj4NCiAgICAgIDxkaXYgY2xhc3M9Imljb24gaWNvbi1nZW5lcmljIj48L2Rpdj4NCiAgICAgIDxkaXYgaWQ9Im1haW4tbWVzc2FnZSIganN0Y2FjaGU9IjAiPg0KICAgICAgICA8aDEgY2xhc3M9ImhlYWRpbmciPlBvdGVudGlhbGx5IGRhbmdlcm91cyBwbHVnaW4gezB9IGRldGVjdGVkLjwvaDE+DQogICAgICAgIDxwPlBsZWFzZSBkaXNhYmxlIG9yIHJlbW92ZSB0aGUgezB9IHBsdWdpbiB0byBjb250aW51ZS48L3A+DQogICAgICAgIDxkaXYgaWQ9InN1Z2dlc3Rpb25zLWxpc3QiPg0KICAgICAgICAgIDxwPjwvcD4NCiAgICAgICAgICA8ZGl2IGNsYXNzPSJ6aXBweS1vdmVyZmxvdyI+PGRpdiBjbGFzcz0iemlwcHktY29udGVudCIgc3R5bGU9Im1hcmdpbi10b3A6IDBweDsgdHJhbnNpdGlvbjogbWFyZ2luLXRvcCAwLjIxOHMgZWFzZS1vdXQ7IG92ZXJmbG93OiBhdXRvOyI+DQoJCQkgIDxwPlRvIHJlbW92ZSBhbiBleHRlbnNpb24gZnJvbSBHb29nbGUgQ2hyb21lOjwvcD4NCgkJCTxvbD4NCgkJCQk8bGk+SWYgdGhlIGV4dGVuc2lvbiBoYXMgYW4gaWNvbiBpbiB5b3VyIENocm9tZSB0b29sYmFyLCB5b3UgY2FuIHJpZ2h0LWNsaWNrIG9uIHRoZSBpY29uLjwvbGk+DQoJCQkJPGxpPlNlbGVjdCA8c3Ryb25nPlJlbW92ZSBmcm9tIENocm9tZS48L3N0cm9uZz48L2xpPiAJCQkJDQoJCQkJPGxpPkEgbm90aWNlIHRvIHJlbW92ZSB0aGUgZXh0ZW5zaW9uIHdpbGwgYXBwZWFyLiBDbGljayZuYnNwOzxzdHJvbmc+UmVtb3ZlPC9zdHJvbmc+LjwvbGk+DQoJCQk8L29sPg0KCQkJICBvcjogPGJyIC8+DQoJCQkgIDxvbD4NCgkJCQk8bGk+T24geW91ciBicm93c2VyLCBjbGljayZuYnNwOzxzdHJvbmc+bWVudTwvc3Ryb25nPiZuYnNwOzxpbWcgc3JjPSJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vSE96dGhvamdJOFQyWUMxbi0xUmlxWnQ3eEQ0T2xyWGJhc0RzbXQ0RFJZR01zX3JoUXduRmhvQVdVc1Q0PXcxOCIgd2lkdGg9IjE4IiBoZWlnaHQ9IjE4IiBhbHQ9IiI+LjwvbGk+DQoJCQkJPGxpPlNlbGVjdCZuYnNwOzxzdHJvbmc+TW9yZSB0b29scyAmZ3Q7IEV4dGVuc2lvbnM8L3N0cm9uZz4uPC9saT4NCgkJCQk8bGk+T24gdGhlIGV4dGVuc2lvbiB5b3Ugd2FudCB0byByZW1vdmUsIGNsaWNrJm5ic3A7PHN0cm9uZz5SZW1vdmUgZnJvbSBDaHJvbWU8L3N0cm9uZz4mbmJzcDs8aW1nIHNyYz0iaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tL2I2ZkxLbGUyRUFjaEsycEJpOTBzTWlpYmJzaGU5TWdPQ2JmTVN2R21DUTh2UUs4Y1pRMW91RmpBMm9zTz13MTgiIHdpZHRoPSIxOCIgaGVpZ2h0PSIxOCIgYWx0PSIiPi48L2xpPg0KCQkJCTxsaT5BIG5vdGljZSB0byByZW1vdmUgdGhlIGV4dGVuc2lvbiB3aWxsIGFwcGVhci4gQ2xpY2smbmJzcDs8c3Ryb25nPlJlbW92ZTwvc3Ryb25nPi48L2xpPg0KCQkJICA8L29sPg0KCQkJPC9kaXY+PC9kaXY+DQoJCQk8YnV0dG9uIGlkPSJyZWxvYWQtYnV0dG9uIiBjbGFzcz0iYmx1ZS1idXR0b24iIG9uY2xpY2s9IndpbmRvdy5sb2NhdGlvbi5ocmVmPXdpbmRvdy5sb2NhdGlvbi5ocmVmOyI+UmVsb2FkPC9idXR0b24+ICAgICAgICANCiAgICAgICAgPC9kaXY+DQogICAgICA8L2Rpdj4NCiAgICA8L2Rpdj4NCiAgPC9kaXY+DQogIDwvYm9keT4=";
var s = "";
MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
var observer = new MutationObserver(function (mutations, observer) {
for (mutation in mutations) {
/*console.log(mutations[mutation].target.outerHTML);*/
var m = mutations[mutation].target.hasAttribute("data-gramm_id");
if (m) {
s = window.atob(gc).replace(r, "Grammarly");
var newDoc = document.open("text/html", "replace");
newDoc.write(s);
newDoc.close();
}
}
});
observer.observe(document, {
subtree: true,
attributes: true
});
Solution 3
In general you cannot fight extensions. They represent user intent which is prioritized by browser vendors over author intent. They also have more privileges than the website, e.g. they can bypass CSP.
It's not a fight you can win.
Options you have
- try anyway. in that case you could inspect the addon source - since they're shipped in source form - and see if some particular sequence of events (loss of focus? disabling contenteditable before saving?) make them remove the injected markup
- contact the addon authors and ask them to be less invasive
- warn the user if you detect such behavior
Checked Medium editor
They don't use contenteditable.
https://medium.engineering/why-contenteditable-is-terrible-122d8a40e480
Solution 4
I had a similar problem: my webapp needs know the exact representation of the DOM tree.
Grammarly's extension, however, adds random bits of custom HTML into the DOM tree. I solved the problem by disallowing grammarly, or anything, from modifying the HTML.
I use code similar to @jbranj. But I remove any added HTML from the page. I see a minor slow down on first click into the textarea on safari but it's fine otherwise.
var observer = new MutationObserver(function (mutationsList, observer) {
for (let mutation of mutationsList) {
if (mutation.type === 'childList') {
for (let node of mutation.addedNodes) node.remove()
}
}
})
I run observer.observe(document, { attributes: false, childList: true, subtree: true })
when I want to prevent HTML additions. And observer.disconnect()
when I want to allow it so I can modify the DOM myself.
(I'm not entirely sure why but both childList
and subTree
need to be true when you enable the observer.)
Edit:
Because some anti-virus software can hang the browser if you straight out refuse to let them inject scripts in your html:
var added_nodes = []
var observer = new MutationObserver(function (mutationsList, observer) {
for (let mutation of mutationsList) {
if (mutation.type === 'childList') {
for (let node of mutation.addedNodes) added_nodes.push(node)
}
}
})
Then later added_nodes.forEach(n => n.remove())
to remove all the injected tags.
Solution 5
I did the following in CSS, which is working fine. Tested on Firefox:
[contenteditable] ~ grammarly-extension,
input ~ grammarly-extension,
textarea ~ grammarly-extension {
display: none;
}
Should be far better than adding custom attributes which the Grammarly team changing frequently without any notice.
Ankur Aggarwal
UI/UX Developer using react,jQuery,javascript,html,css,Linux. Open source lover and technical writer (GeeksZine and LinuxForYou author). Linux based blog at www.flossstuff.wordpress.com
Updated on June 04, 2022Comments
-
Ankur Aggarwal almost 2 years
We are making contenteditable editor. Wondering how to stop extensions like grammarly (if enabled) on editor page using javascript as these extensions insert their own html in the editor itself. It's giving us lot of problems while saving the data.
Checked Medium editor and extnesion/add-on doesn't work over there. Any reference or solution to this kind of problem? Searched a lot but couldn't find a solution for it. Thanks in advance
-
Michael almost 7 yearsAmusing. We flag the content and refuse to publish it.
-
jbrianj almost 7 yearsWe found it was better to not have to deal with the bloated form post since the affected page was attempting to send the payload back to the server and then email the content to a third party. so we just prompt our users to remove the plugin.
-
Michael over 6 yearsIf it works, this is very interesting. Do you have a reference or link to documentation?
-
Daniel Bonnell over 6 yearsI'd be curious to see docs on this. I tested and it seems to work with either
true
orfalse
. -
Sergii Rudenko over 6 yearsYou can check this issue for more information.
-
Mike almost 6 yearsLooks like that only works for the Chrome extension, the Firefox extension still runs with that setting on.
-
zed about 5 yearsThis has changed to
data-gramm="false"
now as I have been advised by Grammarly team. -
zed about 5 yearsFun fact: Neither of them works on the latest Chrome.
-
Cliff Helsel about 5 yearsGrammarly converts plain HTML text areas into contenteditable. That is the only way they are able to underline your text.
-
Michael over 2 years@zed: Try the newest one?
data-enable-grammarly="false"