Accessing DOM elements with JavaScript in themes

Hey everyone @2021-FS-L-S1 @2021-FS-P-S1 ,

This issue was posed, and I think it’s important that everyone knows about this as well.

When developing a theme or theme component and trying to access elements in the DOM, you may notice that you are unable to do so and you might have seen the output as null when logged.

For example in your theme if you try and add the following code to your after_header.html, in hopes of making a button change a text style, it will not work:

<script type="text/discourse-plugin" version="0.8">
    document.getElementById('myButton').onclick = function () {
      document.getElementById('myText').style.color = 'red';
    };
</script>

The reason this is so is because your selector is likely running before the page has rendered the template. This is because Discourse is built as a ‘web app’ not a ‘web page’. As a result, the elements on the page are dynamic not static. The document object is rendered once, but certain elements are not rendered immediately because they are Ember components.

Read more about the component lifecycle here:

So, how can you select elements in the DOM?

There are a couple of approaches. For more complex changes, it may be beneficial to create an Ember component.

Learn more here:

Another, more simpler approach would be to make use of Discourse’s plugin API. You can for example, detect for changes on a page using the api.onPageChange() method.

To convert our previous example, we can do something like this:

<script type="text/discourse-plugin" version="0.8">
  api.onPageChange(() => {
    document.getElementById('myButton').onclick = function () {
      document.getElementById('myText').style.color = 'red';
    };
  });
</script>

I hope this helps! Have fun theming! Please let me know if you have any questions :point_down:

4 Likes