The past few days, I’ve been working on a one page site for a long term client and came across the issue of all my menu items for anchor links in Kadence being highlighted at the same time. The Kadence customiser provides fantastic settings for styling your menus, but it assumes you’re working on a standard, multi-page site. If you use custom links in your menu to jump to different anchor points within a page (blocks with an HTML anchor added), then whenever you are on that page, all those anchor links will be highlighted as active in your menu.

Not sure what I mean? Allow me to illustrate:

Highlight anchor links in Kadence menus


See how all the menu items are a coral colour except for the blog? That’s because they’re all anchored to row blocks on the page, but the blog is its own page, so its link is white, as it should be until it’s the active page.

Not ideal.

I know my way around jQuery reasonably well, and I when I’ve created one page sites in Divi, I have a standard script in my snippets library so it’s just a matter of copy/paste. I could have modified this for use with Kadence, but as Kadence is moving away from jQuery I wanted a vanilla Javascript solution to this anchor link issue. The only problem…I’m totally crap at Javascript 🤣

And then I remembered something!

TLDR: If you’re not interested in reading about my reluctant expedition to the world of AI and how I prompted it to write this function for me, jump straight to the working code.

A few months ago, I had a conversation with Kathy from KadenceWP about AI. I’m a writer (or trying to be 😉), and I have a fierce loathing of AI and its bland, voiceless prose, but Kathy wanted me to beta test Kadence’s upcoming AI integration, and when Kathy asks, the answer is always yes.

Up until that conversation, I had avoided AI like kale, but after speaking with Kathy I put my loathing on a high shelf and dived into ChatGPT. I know what you’re thinking…you’re thinking I was an immediate convert and I loved the copious amount of words a software program wrote for me in a matter of seconds. Well, you’re wrong, I still hated it.😜 But…a few weeks later I found a potential use for it.

When I create my WordPress child themes, other than the marketing funnels which include copy prompts, I usually fill out the content sections with Hipsum (Hipsum.co, my preferred alternative to Lorem Ipsum). I’ve been working on a new photography child theme in the three minutes a day I get to myself, and I thought, hmm…I wonder if ChatGPT can generate me some semi-decent words for my child theme. And it did!

With the right prompts, the friendly bot spat out reams of insipid content for me to copy/paste into my child theme’s content sections. No, it’s not the most engaging text to read, and yes, you can tell a mile off it’s AI generated content, but that’s fine. Most people find writing content for the web difficult, and there is nothing more daunting than a cursor flashing on a blank page, but with a jumping off point courtesy of ChatGPT, customers who purchase my new theme can use the base text to craft their own words in their own voice, and get their web copy written a whole lot faster. That’s added value.

So, back to the point of this post 👀

Following my success with child theme demo content, I decided to employ ChatGPT as my new unpaid intern, and get it to write my vanilla JavaScript function to highlight active anchor links in Kadence for me 😁

It wasn’t straightforward, but it was a whole lot faster than taking a coding course. If you’re not interested in the process and prompts I used to get ChatGPT to spit out a working function, use the table of contents below 👇🏻 to skip straight to the code. But if you intend to use the smart bot to write some code for you, then checking out how I wrote my prompts might help you in getting your desired output.

So let’s get to it!

My conversation with ChatGPT

I’m going to show you the whole conversation but leave out all the code ChatGPT provided that didn’t meet my requirements and only include the finished, working code that highlights active anchor links in Kadence for both desktop and mobile menus. For visual ease, my prompts are in yellow, and ChatGPT’s responses are in pink.

Here’s how I kicked things off:

Write me a vanilla JavaScript function for WordPress that highlights an anchor link item when the corresponding section reaches the top of the browser window.

Certainly! Here’s a vanilla JavaScript function that can be used in WordPress to highlight an anchor link item when its corresponding section reaches the top of the browser window:

(Code omitted)

Make sure to add the CSS class .highlighted to your stylesheet to define the desired style for the highlighted anchor link. You can modify the CSS class to match your preferred styling:

This gave the basis for the code, but I wanted it to be specific to the primary navigation only…

Limit this function to links within an HTML element with the class ‘main-navigation’

To limit the function to only consider anchor links within an HTML element with the class ‘main-navigation’, you can modify the querySelectorAll selector in the code. Here’s the updated version of the function:

(Code omitted)

The code ChatGPT gave me didn’t work, and I thought it might have something to do with the selector not being close enough in the DOM to the target, so I revised using the menu link item’s parent container, and an ID instead of a class…

Cancel the last revision and limit this function to links that are children of an HTML element with the ID ‘primary-menu’

Apologies for the confusion. To limit the function to consider only anchor links that are children of an HTML element with the ID ‘primary-menu’, you can make the following adjustments:

(Code omitted)

The code I got this time didn’t work…

This isn’t working. The highlighted class isn’t being added.

I apologize for the oversight. It seems I missed a small error in the code. Please try the following revised version:

(Code omitted)

👆🏻 ChatGPT can debug itself 🤯

It’s still not adding the highlighted class.

I apologize for the inconvenience. Let’s try a slightly modified approach to ensure the class is added correctly. Please use the updated code below:

(Code omitted)

By this point, I’m pretty sure ChatGPT is English (even if it can’t spell apologise correctly). No other nation apologises as much as we do 😉

Still not working. The anchor link is in the following format /#anchor and its parent is an li element. Does that make a difference?

Apologies for the confusion. If the anchor links are in the format /#anchor and their parent is an li element, we need to modify the code accordingly. Please try the following revised version:

(Code omitted)

This is working! However, if a section doesn’t fill the height of the screen, the menu item for the next section is also highlighted. Please adjust so the highlight is only applied when the section reaches the top of the screen.

Apologies for the oversight. To ensure that the highlight is only applied when the section reaches the top of the screen, we need to make a small adjustment to the code. Please try the following updated version:

(Code omitted)

The outputted code did work, but…

The menu item should highlight when the user scrolls too. Currently it’s working when they scroll up, but not down.

Apologies for the confusion. To ensure that the menu item highlights when the user scrolls down as well, we need to adjust the code accordingly. Please try the following updated version:

(Code omitted)

That has fixed the scroll up and down issue. However, it’s still highlighting multiple items at once. The item shouldn’t highlight until the top of its section reaches the top of the browser window.

Apologies for the confusion. To ensure that only one menu item is highlighted at a time, and that it highlights when the top of its section reaches the top of the browser window, we can make further adjustments to the code. Please try the following updated version:

(Code omitted)

Almost. The highlight is being applied when the section is first visible in the viewport. Let’s try and add it when it’s 50% in the viewport.

Not gonna lie, by this point I’m pretty damn impressed!

Apologies for the confusion. To apply the highlight when the section is at least 50% visible in the viewport, we can update the threshold value and adjust the logic accordingly. Please try the following updated version:

(Code omitted)

This version of code worked perfectly. My menu items highlighted on both click and scroll, up and down, and only the section properly inside the viewport was allocated the ‘highlighted’ class.

But I’m a perfectionist, and I knew ChatGPT could do better. While this code worked just fine, it did rely on CSS to style the active menu item. No big deal to add a single line of CSS, but as I said earlier, the Kadence Customiser gives us fantastic settings for styling our menus, and I wanted to make use of those features.|

When a page is being viewed, Kadence gives the corresponding menu item two CSS classes: ‘current-menu-item’ and ‘current_page_item’, and those classes are used by the static, hover, and active colours you choose in your menu settings. So…

This works! Now can you adjust it so that the classes ‘current-menu-item’ and ‘current_page_item’ are also added and removed from the li element.

Certainly! To add and remove the classes ‘current-menu-item’ and ‘current_page_item’ from the element along with the ‘highlighted’ class from the corresponding anchor link, we can update the code as follows:

(Code omitted)

Great. Now please adjust so it only adds the classes to the li element and not the highlighted class to the a element.

Apologies for any confusion. If you only want to add the classes ‘current-menu-item’ and ‘current_page_item’ to the element without adding the ‘highlighted’ class to the corresponding anchor link, you can update the code as follows:

(Code omitted)

Can we make this work for the the ID ‘mobile-menu’ as well?

Certainly! To make the highlighting functionality work for the ‘primary-menu’ as well as the ‘mobile-menu’ ID, you can modify the code as follows:

(Code omitted)

In this updated version, we have added support for the ‘mobile-menu’ ID. The code now creates separate anchor link and list item collections for both the ‘primary-menu’ and ‘mobile-menu’ elements. The handleHighlight function is used to handle the highlight logic for both menus.

And…Bingo 👊🏻
There were a few further minor adjustments I had ChatGPT make, but this was pretty much the finished code.

That works perfectly, thanks for your help, ChatGPT.

You’re welcome! I’m glad to hear that it works perfectly now. If you have any more questions or need further assistance, feel free to ask. Happy coding!


Key takeaway: ChatGPT is one polite mofo!

The working code to highlight active anchor links in Kadence menus

Here is the code you need in all its AI glory. Add it to the footer area in the customiser’s Custom Scripts section if you’re using Kadence Pro, or a code snippets plugin if you prefer. Don’t forget to surround it in <script> tags.</script>

function highlightAnchorLinks() {
  // Get the menu elements
  const primaryMenu = document.getElementById('primary-menu');
  const mobileMenu = document.getElementById('mobile-menu');

  // Get all anchor links within the primary menu
  const primaryAnchorLinks = primaryMenu.querySelectorAll('li > a[href^="/#"]');
  // Get all anchor links within the mobile menu
  const mobileAnchorLinks = mobileMenu.querySelectorAll('li > a[href^="/#"]');

  // Create an intersection observer instance for the primary menu
  const primaryObserver = new IntersectionObserver(entries => {
    entries.forEach(entry => {
      const targetId = entry.target.getAttribute('id');
      const listItem = primaryMenu.querySelector(`li > a[href="/#${targetId}"]`).parentNode;

      if (entry.isIntersecting && entry.intersectionRatio >= 0.5) {
        const activeListItem = primaryMenu.querySelector('.current-menu-item');

        if (activeListItem) {
          activeListItem.classList.remove('current-menu-item', 'current_page_item');
        }

        listItem.classList.add('current-menu-item', 'current_page_item');
      } else {
        listItem.classList.remove('current-menu-item', 'current_page_item');
      }
    });
  }, { threshold: [0.5] });

  // Create an intersection observer instance for the mobile menu
  const mobileObserver = new IntersectionObserver(entries => {
    entries.forEach(entry => {
      const targetId = entry.target.getAttribute('id');
      const listItem = mobileMenu.querySelector(`li > a[href="/#${targetId}"]`).parentNode;

      if (entry.isIntersecting && entry.intersectionRatio >= 0.5) {
        const activeListItem = mobileMenu.querySelector('.current-menu-item');

        if (activeListItem) {
          activeListItem.classList.remove('current-menu-item', 'current_page_item');
        }

        listItem.classList.add('current-menu-item', 'current_page_item');
      } else {
        listItem.classList.remove('current-menu-item', 'current_page_item');
      }
    });
  }, { threshold: [0.5] });

  // Observe each section for the primary menu
  primaryAnchorLinks.forEach(anchorLink => {
    const targetId = anchorLink.getAttribute('href').substring(2); // Remove leading "/#"
    const section = document.getElementById(targetId);

    if (section) {
      primaryObserver.observe(section);
    }
  });

  // Observe each section for the mobile menu
  mobileAnchorLinks.forEach(anchorLink => {
    const targetId = anchorLink.getAttribute('href').substring(2); // Remove leading "/#"
    const section = document.getElementById(targetId);

    if (section) {
      mobileObserver.observe(section);
    }
  });
}

// Call the function when the DOM is fully loaded
document.addEventListener('DOMContentLoaded', highlightAnchorLinks);

How to create your anchor links in Kadence menus

Add an HTML anchor to each row or section in your page you want to link to, then create the corresponding custom menu links items in Appearance > Menus.

I created my custom menu links to my anchor points in the following format:

/#anchor

The one page site I added this code to also has a blog and archives, and I wanted to make sure if the user clicks on a menu item whilst inside the blog, the links still take them back to the main page. That’s what the leading slash is for, and the JavaScript accounts for this format. So if you use the code, you’ll need your anchor links formatted the same way.

Getting FOUC?

Depending on your optimisation settings, you could experience a little FOUC (Flash of unstyled content) whereby all anchors display as highlighted for a nanosecond before settling to their static colour. If this happens you have a couple of options:

1) Move the JavaScript to the header section instead of the footer so it loads earlier.
2) Add a little CSS to subtly fade in the menu links so the FOUC happens before the links are visible.

Both options can have an impact on page speed results, but it’s minor and you’ll have to decide on the best option for your use case.

Here’s the CSS. We only need to apply it to the desktop menu as the mobile menu is off-screen on page load. You can adjust the 500ms (half a second) value in the animation property and see how low you can get it while still eliminating the FOUC.

#primary-menu li {
  animation: fadeIn 500ms;
}

@keyframes fadeIn {
  0% { opacity: 0; }
  100% { opacity: 1; }
}


And that’s it. Now you can highlight your active anchor links in Kadence menus for one page or multi-page sites.

I won’t go so far as to say I’m an AI convert. I tried out Jasper Art this weekend to see whether it could design a better book cover than I did for my friend’s latest novel and the results were hilarious. 7 fingers and 2 noses, the moon was a squashed oval, and the buildings looked like the backdrop from a Tom & Jerry cartoon.

Conclusion: ChatGPT has earned itself a coveted spot on my crowded bookmarks toolbar. It can’t make me coffee yet or field client emails, but AI definitely has its place, it just better stay there 😁

Michelle x

Kadence tutorial request
First
Why? I might have questions, and if I create a solution I’ll let you know.
How do you prefer to consume tutorial content?
This helps me to determine the preferred content format.

Pro Pass Membership

Want access to all current and future child themes, kits, and our B&B Blocks library for Kadence for one low annual price?

Brand & Build Pro Pass

Latest

In the shop

  • Kadence
    Lane Wordpress Theme for KadenceLane Wordpress Theme for Kadence

    for content creators

    £175.00

    View Details 🡢

  • Kadence
    Liora Child Theme for KadenceLiora Child Theme for Kadence

    for bloggers

    £175.00

    View Details 🡢