Can't get js() helper to link to my javascript file

I have some javascript which I’m very certain works because when I use it in the body between <script> tags it works fine. But I want to move the javascript to a separate .js file. So I’ve created a Javascript file called scripts.js in the Assets folder.

Then in the head I’m trying to link to it:

<?= js('assets/scripts.js') ?>

But the javascript is either stopped working, or is not linked to correctly.

Here’s the content of the .js file:

/** select the button that opens the nav */
const menuOpener = document.querySelector('.nav-button');

/** apply a click event handler that simply toggles the ".show-nav" class on the body */
menuOpener.addEventListener('click', () => document.body.classList.toggle('nav-shown'));

What am I doing wrong?

Is the file located directly in assets or in a js subfolder maybe?

When you check the network tab in dev tools, do you get a 200 or 404 http code for the file?

Directly in the assets folder

In the Dev Tools Javascript Console I get the following error message:

Uncaught TypeError: Cannot read properties of null (reading ‘addEventListener’)
at scripts.js:5:12

Not sure how to check this “When you check the network tab in dev tools, do you get a 200 or 404 http code for the file?”

That looks like the script is actually loading since you are getting a console error in the browser.

Some scripts need to go just before the closing body tag since they need the page to be full loaded. As you have put this script in the head, it is trying to access a part of the page that hasnt been loaded yet.

just move the <?= js('assets/scripts.js') ?> line to just before the closing body tag.

1 Like

Thank you. That’s done the trick

For future completeness: you could also leave it in the <head>, but add a defer attribute to it. In fact, by many this is considered preferable, because it allows the browser to know about the script earlier.

The defer attribute basically makes the browser download the script as soon as it sees the tag, it doesn’t block the parser like “normal” scripts do, and the script is executed only after the whole document has been parsed, but before DOMContentLoaded is fired.

In Kirby you can add a defer attribute to the script tag by adding it to the options array of the js helper:

<?= js('assets/scripts.js', ['defer' => true]) ?>
1 Like