skip to Main Content

I’ve recently become fascinated with how tools like LanguageTool and Grammarly show red underlines on mispelled words on the screen. I’d like to do something similar but to show rich popovers with things like synonyms on hover of a word after first showing an underline on said word.

This is not about browser extensions. See the links I’ve included to Grammarly’s SDK plugins & LanguageTool’s API examples.

I know Grammarly is using the Shadow DOM with slots to wrap the textarea, but I still can’t tell how they’re able to (efficiently) determine the position of a specific word in the textarea. LanguageTool doesn’t use the Shadow DOM.

Neither duplicate show cloned HTML when I inspect it, which I thought they might in order to some how break the text into tokens that they could get bounding rects for — but that doesn’t appear to be it.

The result of using <grammarly-editor-plugin><textarea></textarea></grammarly-editor-plugin>
enter image description here

LanguageTool example:
enter image description here

I tried using the Canvas API to get the dimensions of a specific word, but that isn’t enough to determine its position in the textarea because the word could be on a line greater than the first.

In order to make this approach work, they have to be getting all the words in the textarea, computing their dimensions, and using the dimensions of the textarea to determine which line a target word is in the textarea; together with the dimensions, specifically the width, of the word, they would then have the x & y positions within the textarea. However, this seems too expensive and slow to pull off as fast as their underlines appear to show.

I could go with contenteditable by just wrapping each word in its own span, but that seems less than ideal.

Does anyone else know how else they could be able to determine the X & Y position of a word in a textarea.

2

Answers


  1. You got me all fired up but it didn’t turn out to be much of a challenge! 🙁

    <!DOCTYPE html>
    
    <head>
    
    <style>
    
    u{color:red;}
    
    .con{width:500px; height:100px; border:1px solid black;}
    
    </style>
    
    </head>
    
    <body>
    
    <script>
    
    const Correct=['Once','upon','a','time','there','were','three','little','pigs'];
    
    
    function CheckSpelling(){
    
    var S=Con.innerHTML.replace(/<u>/g,'').replace(/</u>/g,'');
    
    var A=S.split(' ');
    
    for(let i=0; i<A.length; i++){
    
     if(Correct.includes(A[i])===false){A[i]='<u>'+A[i]+'</u>';}
    
    } Con.innerHTML=A.join(' ');}
    
    
    </script>
    
    Change the words below and click spellcheck...<br><br>
    
    <div id="Con" class="con" spellcheck="false" contenteditable="true">Once upon a time there were three little pigs</div>
    
    <br>
    
    <button onclick="CheckSpelling();">Check Spelling</button>
    
    <br><br>
    
    NB: Optionally you can automate the spellcheck by adding a oninput="CheckSpelling();" to the container.
    
    </body>
    
    </html>
    
    Login or Signup to reply.
  2. On macOS, Grammarly uses the Accessibility API for getting and setting values and properties of controls (selection, text content, character position, caret position, etc.). For changing texts, it emulates keystrokes. For underlining the text, it uses an overlay window.

    I suppose that on MS Windows, it uses equivalent techniques (the UIAutomation API and overlay windows).

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search