lauragift21
lauragift21

Reputation: 117

How to fix navbar overlap on dropdown items with a vuepress site

There's always an overlap with Navbar dropdown when more than one is clicked. It focuses and takes a few minutes to clear this becomes a problem because it causes clutter.

The configuration for this in the Vuepress docs is just to add navbar items and ariaLabel any know how I can stop this behaviour.

themeConfig: {
    nav: [
      {
        text: 'Languages',
        ariaLabel: 'Language Menu',
        items: [
          { text: 'Chinese', link: '/language/chinese/' },
          { text: 'Japanese', link: '/language/japanese/' }
        ]
      }
    ]
  }

Here's an example vuejs events site FD Guide

Upvotes: 1

Views: 677

Answers (1)

tao
tao

Reputation: 90068

To answer your question one would need to address two distinct issues:

  • how do I run custom JavaSCript in VuePress?
  • how do I close any previously open dropdowns on click in my current VuePress theme, using JavaScript?

For the first problem there are several solutions (one of them being by using a custom component with code run in its mounted() hook, but this would require you to include that component in every page and make sure it doesn't run more than one time (since you want to bind events to elements).
I believe the cleanest way would be by adding a <script> to <head> which can be achieved by adding this to the head prop of your .vuepress/config.js export:

head: [
  // ...existing stuff, if any,
  ['script', {}, `
    (function() { 
      // your code here...
    })(); 
 `]
]

However, there are a few problems with the above solution. Firstly, it's going to be run as soon as it's parsed, and that's inside the <head> tag. Which means none of the contents of your page are rendered yet. And the second problem is you're in a template literal. You don't really want to be writing JavaScript code in a template literal. Ideally you should be able to put your code in a '.js' file and append it as a <script> tag.

In order to do that, you need to create a .vuepress/public/ folder, if you don't already have one. Place your .js file in there (I used test.js but feel free to name it as you like). Modify the above code to:

['script', {}, `
  (function() { 
    var s = document.createElement('script'); 
    s.src = './test.js'; 
    var h = document.querySelector('head'); 
    h.appendChild(s); 
  })();
`]

Change ./test.js to your file's name.

Now your file has clean JavaScript and the door is open. Your code executes in the window object context.


To answer the second part of your question, well..., it largely depends on the theme you are using. If you're using the default theme (which seems to be the case, from the SS you posted), this should work, if placed inside your .js file:

document.addEventListener('DOMContentLoaded', fixDropDowns);
function fixDropDowns() {
    document.body.addEventListener('click', (ev) => {
        const header = document.querySelector('header');
        if (header) {
            const dds = header.querySelectorAll('.dropdown-wrapper');
            [...dds].forEach(el => el.classList.remove('open'));
            const curr = ev.target.closest('.dropdown-wrapper');
            if (curr) {
                curr.classList.add('open');
            }
        }
    })
}

But it's based on a close inspection of the generated markup.
Specifically on the fact the dropdowns have a class of .dropdown-wrapper and that they're opened by toggling class open on them. The above is just an example and will likely not work on other themes and might even stop working on the default theme in some future version.

Upvotes: 1

Related Questions