Search code examples
javascripthtmliframe

Using getElementByID or QuerySelector from inside iFrame does not work


I have a really weird behaviour right now in production which is that, on a Single Sign-On login page (we are the SSO provider), some JS selectors instructions are not working when the page is loaded through an iFrame on another website.

The selectors are executed on the login page template, on my side (the SSO side), they are not executed on the page hosting the iFrame. Still, they return null.

HTML code:

<document>
<body>
  <script>
    if (window.parent != window) {
      window.document.getElementById('content').style.padding = '0';
    }
  </script>
  <div class="container">
    <main id="content" class="flex-column">
       <div class="sib-login-title">
         You need to login to access this page
       </div>
    </main>
  </div>
</body>
</document>

The code here is really basic because I extracted the base elements, what's weird is that, when accessing my login page in the browser and executing the getElementById in the console, it works:

window.document.getElementById("content");
<main id="content" class="flex-column">

Same code from the script tag when the page is loaded through an iframe returns:

?next=/authorize/%3Fclient_id%xxxxxxxxxxxxxxxx%26response_type%3Dcode%26scope%3Dopenid%2520profile%2520email%2520preferred_username%2520roles%26redirect_uri%3Dhttps%3A//xxxxxxxx/auth:42 Uncaught TypeError: Cannot read properties of null (reading 'style')

I want to emphasize that this script tag is really on the document loaded through the iframe, not on the parent document loading the iframe, so I really do not get why.

I checked a lot of questions on SO but they are all asking how to access elements inside the iframe from the parent document, that's not my scenario here.

Any ideas ? Something I forgot about ?

Thanks in advance.


Solution

  • The JavaScript is trying to reference the element before it exists (it exists a couple of lines later, so you're just a bit keen).

    You just need to put things in the correct order, like this:

    #content {
        padding: 100px;
    }
    <div class="container">
      <main id="content" class="flex-column">
         <div class="sib-login-title">
           You need to login to access this page
         </div>
      </main>
    </div>
    <script>
        if (window.parent != window) {
          document.getElementById('content').style.padding = '0';
        }
    </script>