How to create and use custom elements in extensions?

73 Views Asked by At

I am developing an chrome extension specifically for gmail. For my use case, I want to inject button nearby the send button of gmail. My button will contain some options in it. It will be displayed when user clicks on the button and further implementation should be done.

To achieve this, I have already tried with iframe approach.Which means, I will have seperate files [ HTML , CSS , JS ] for my button. When button click happens , the a list will be displayed and that also i kept it there. I provided them in web_accessable_resources in manifest.json file. It works fine.

But I face few issues in using iframe like when user right clicks on iframe. the loadFrame option will be available and if it is clicked then the frame get vanised and user need to refresh to see it. This is not a good user experience.

So, I decided to go for another approach which is custom elemnts.

With this i need to create my custom element using webCompocnents and need to use it in content-script.

As customElements API is null in content-script file , i created another js file and created my custom element (basic) there and used that custom element in my content script. I have used innerHTML to define my custom element. my custom elemnt is get placed in the gmail as i expected.

But my custom element is not simple. As i said earlier it requires seperate HTML , CSS and JS. There will be message passing to another part of extension using chrome API's. But , I am unable to load seperate HTML , CSS file in my innerHTML.

strunctute :

src 
|
---manifest.json
|
|
---gmail-compose-assistant.js (content-script) 
|
|
---custom-elements
   |
   |
   --gmail-compose-assistant-element.js
   --gmail-compose-assistant-element.html
   --gmail-compose-assistant-element.css


manifest.json :


{
  "name": "###",
  "description": "An AI companion.",
  "version": "1.0.1",
  "manifest_version": 3,
  "action": {
    "default_icon": "###",
    "default_title": "Click me!"
  },
  "icons": {
    "16": "###",
    "32": "###",
    "48": "###",
    "128": "###"
  },
  "background": {
    "service_worker": "background.js"
  },
  "content_scripts": [
   {
      "matches": ["*://mail.google.com/*"],
      "js": ["gmail-compose-assistant.js"],
    }
  ],
  "content_security_policy": {
    "extension_pages": "script-src 'self'; object-src 'self'"
  },
  "web_accessible_resources": [
    {
      "resources": [
        "/custom-elements/gmail-compose-assistant-element.html",
        "/custom-elements/gmail-compose-assistant-element.css",
        "/custom-elements/gmail-compose-assistant-element.js"
      ],
      "matches": ["<all_urls>"]
    }
  ]
}

content-script [ gmail-compose-assistant.js ]:

const script = document.createElement('script');
script.type = 'module';
script.src = chrome.runtime.getURL('/custom-elements/gmail-compose-assistant-element.js');
document.body.appendChild(script);

const observerConfig = {
  childList: true,
};

const observer = new MutationObserver(observeDocumentBody);
observer.observe(document.body, observerConfig);

function injectDummyText(element, index) {
  const newTabledataRef = document.querySelector('#newTableData' + index);
  const tableRow = element.querySelector('tr');

  if (!newTabledataRef) {
    const tableData = tableRow.insertCell(1);
    const customElement = document.createElement('custom-gmail-compose-assistant');
    tableData.appendChild(customElement);
    tableData.id = 'newTableData' + index;
    console.log('tableData', tableData);
  }
}

function observeDocumentBody() {
  const tableElemets = document.getElementsByClassName('IZ');
  if (tableElemets.length) {
    Object.values(tableElemets).forEach((element, index) => {
      injectDummyText(element, index);
    });
  }
}

gmail-compose-assistant-element.js:

const template = document.createElement('template');

fetch(chrome.runtime.getURL('./gmail-compose-assistant.html')).then((response) =>
  response.text().then((html) => {
    template.innerHTML = html;

    const styleSheetLink = document.createElement('link');
    styleSheetLink.rel = 'stylesheet';
    styleSheetLink.href = chrome.runtime.getURL('./gmail-compose-assistant.css');
    template.content.prepend(styleSheetLink);
  })
);


class CustomGmailComposeAssistant extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    this.shadowRoot.appendChild(template.content.cloneNode(true));
  }
}

window.customElements.define('custom-gmail-compose-assistant', CustomGmailComposeAssistant);

export default CustomGmailComposeAssistant;

I face below error:

Uncaught TypeError: chrome.runtime.getURL is not a function at gmail-compose-assistant-element.js:3:22

So please help me in this.

Advance thanks.

0

There are 0 best solutions below