How to stop extensions/add ons like grammarly on contenteditable editors

18,640

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.

Share:
18,640
Ankur Aggarwal
Author by

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, 2022

Comments

  • Ankur Aggarwal
    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
    Michael almost 7 years
    Amusing. We flag the content and refuse to publish it.
  • jbrianj
    jbrianj almost 7 years
    We 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
    Michael over 6 years
    If it works, this is very interesting. Do you have a reference or link to documentation?
  • Daniel Bonnell
    Daniel Bonnell over 6 years
    I'd be curious to see docs on this. I tested and it seems to work with either true or false.
  • Sergii Rudenko
    Sergii Rudenko over 6 years
    You can check this issue for more information.
  • Mike
    Mike almost 6 years
    Looks like that only works for the Chrome extension, the Firefox extension still runs with that setting on.
  • zed
    zed about 5 years
    This has changed to data-gramm="false" now as I have been advised by Grammarly team.
  • zed
    zed about 5 years
    Fun fact: Neither of them works on the latest Chrome.
  • Cliff Helsel
    Cliff Helsel about 5 years
    Grammarly converts plain HTML text areas into contenteditable. That is the only way they are able to underline your text.
  • Michael
    Michael over 2 years
    @zed: Try the newest one? data-enable-grammarly="false"