2

tldr: I'm looking to keep the other text in the srcdoc attribute of an iframe alone, but only swap out the link to the stylesheet using vanilla Javascript.

Longer version:

I'm customizing a Publii blog template and embedding a Cusdis comment widget using their hosted JS SDK.

Publii makes use of HTML, CSS, Javascript, and Handlebars.

The Cusdis widget works by pasting the following code in your html document:

<div id="cusdis_thread"
  data-host="https://cusdis.com"
  data-app-id="{{ APP_ID }}"
  data-page-id="{{ PAGE_ID }}"
  data-page-url="{{ PAGE_URL }}"
  data-page-title="{{ PAGE_TITLE }}"
>
<script async src="https://cusdis.com/js/cusdis.es.js"></script>

Then, the Cusdis SDK will find the element with id cusdis_thread, then mount the iframe widget on it:

<iframe srcdoc='<!DOCTYPE html>
 <html>
  <head>
    <link rel="stylesheet" href="https://cusdis.com/js/style.css">
    <base target="_parent" />
    <link>
    <script>
      window.CUSDIS_LOCALE = undefined
      window.__DATA__ = {"host":"https://cusdis.com","appId":"...","pageId":"...","pageUrl":"...","pageTitle":"..."}
    </script>
  </head>
  <body>
    <div id="root"></div>
    <script src="https://cusdis.com/js/iframe.umd.js" type="module"
    </script>
  </body>
 </html>'
style="width: 100%; border: 0px none; height: 323px;">
  #document
</iframe>

My issue is the following:

  • I want to edit the Cusdis widget's CSS so that the look goes better with my site.
  • I've tried editing my own stylesheet and selecting Cusdis's CSS classes, but the changes aren't reflected in the output (even with !important). I suspect that it's because the widget generates an iframe, and the elements I want to edit are contained in the iframe.
  • The workaround seems to be to replace the stylesheet in the iframe's "srcdoc" attribute with a link to another external stylesheet

Because the iframe is automatically generated by Cusdis's SDK, I can't edit that HTML on my end. I'm trying to find a way to replace the stylesheet in the generated iframe's srcdoc using vanilla Javascript.

Here is what I've tried:

Using setAttribute to replace the contents of the attribute:

document.querySelector("#cusdis_thread iframe").setAttribute('srcdoc', '<!DOCTYPE html><html><head><link rel="stylesheet" href="..."><base target="_parent" /><link><script> window.CUSDIS_LOCALE = undefined window.__DATA__ = {"host":"https://cusdis.com", appId":"...","pageId":"{{id}}","pageUrl":"{{url}}","pageTitle":"{{title}}"} </script> </head> <body> <div id="root"></div> <script src="https://cusdis.com/js/iframe.umd.js" type="module"> </script></body></html>');

Result: It worked in theory, but the comment section wasn't generated. When I inspected the code, the attribute's content was replaced. However, I'm using handlebars expressions {{}} to add the PAGE_ID, PAGE_URL, and PAGE_TITLE dynamically, but these expressions are kept inside the srcdoc (so, instead of the iframe displaying the actual URL in the window.__DATA__ =... section, it's still showing the handlebars expression {{url}}).

So, I'm looking for a solution which will keep the other text in the srcdoc attribute alone, but only swap out the link to the stylesheet. Here are my attempts at this:

Using .replace to find the url of Cusdis's stylesheet and replacing it with my own:

document.querySelector("#cusdis_thread iframe").replace("https://cusdis.com/js/style.css", "...");

Result: it was ignored

Using setAttribute for just the stylesheet:

document.querySelector("#cusdis_thread iframe").setAttribute('srcdoc', '<link rel="stylesheet" href="...">');

Result: it was ignored

0

1 Answer 1

4

Since this iframe is loaded through its srcdoc attribute, you can access its inner document from your own document, (because about:srcdoc is magic).

So the best will be to wait for the iframe to load, and to inject your own <link> in there (or modify the StyleSheets as you wish).

const iframe = document.querySelector("iframe");
iframe.addEventListener("load", (evt) => {
  const link = document.createElement("link");
  link.rel = "stylesheet";
  link.href = "your-stylesheet.css";
  iframe.contentDocument.head.append(link);
}, { once: true });

Live Demo (as a jsfiddle because StackSnippets null-origined iframes are dark-magic against same-origin...

The complicated part might be to detect when this iframe is inserted into the document. It seems you already are able to do so, but for the ones who can't, they could either check which event the library fires from, or in worst case scenario, use a MutationObserver.

1
  • Thank you for your speedy reply! Unfortunately, this doesn't seem to do anything on my end... I decided to just self-host Cusdis and edit the css that way. How can someone check which library it fires from? Commented Aug 30, 2021 at 21:19

Not the answer you're looking for? Browse other questions tagged or ask your own question.