How to make all parent menu items clickable (Dawn 15.4)

Topic summary

A user seeks to make parent menu items clickable in Shopify’s Dawn 15.4 theme, wanting them to navigate to linked collections rather than just expanding submenus.

Initial Solutions Attempted:

  • Modifying JavaScript in header.js to prevent default click behavior
  • Adding custom script to theme.liquid file to redirect parent links
  • Multiple script variations with delays and DOM-ready checks

Key Challenge:
Existing hover-to-open submenu code conflicted with the clickable parent solution, preventing it from working on the live theme.

Working Solution:
The code worked successfully on a duplicate Dawn theme. However, clicking parent items initially redirected to the first submenu item instead of the main collection link.

Final Fix (Two-Part):

  1. Modified header-dropdown-menu.liquid (line 19) by wrapping the link title in an anchor tag: <a href="{{- link.url }}">{{- link.title | escape -}}</a>
  2. Added CSS to remove link decoration and color changes:
.list-menu a {
    text-decoration: none !important;
    color: rgba(var(--color-foreground), .75);
}

Resolution: Successfully implemented with parent menu items now clickable and properly styled.

Summarized with AI on October 23. AI used: claude-sonnet-4-5-20250929.

Hello, everyone!
I’d like to make all parent menu items clickable on my website (Dawn 15.4 theme). I want the parent items to open their linked collections when clicked, not only expanding the submenu.

I saw that a solution was shared on the forum earlier, but most of the code has disappeared from the posts, so I can’t use it :frowning:
Can anyone advise? Thank you!

My website: Products – DrawWithDi

1 Like

Hi @DRAWandCARE

Ok dear, please share your store URL and collaborator code with me so I can check and provide you with the proper solution.

To make parent menu items clickable in the Dawn 15.4 theme, go to header.liquid, find the menu loop, and remove or modify the JavaScript or HTML that prevents default link behavior (e.g., e.preventDefault()), allowing parent links to navigate to their assigned URLs.

Hi @DRAWandCARE

Go to Online Store > Themes > Edit Code > assets/header.js

Find the code like below:

this.parentLink.addEventListener(‘click’, (evt) => {
if (this.hasChildren) {
evt.preventDefault();
this.toggleSubmenu();
}
});

Replace it with below code:

this.parentLink.addEventListener(‘click’, (evt) => {
if (this.hasChildren) {
// Only prevent default if the toggle icon/button was clicked
if (evt.target.closest(‘.menu__toggle’)) {
evt.preventDefault();
this.toggleSubmenu();
}
}
});

On click of parent link text it will goes to the linked collection and on Click toggle arrow submenu will expands/collapse.

1 Like

Hi, thank you so much for your reply! Unfortunately, I don’t have a header.js file in my assets. Is there another file where I could add the code?

OK, you can check the code either in below files:

  1. global.js
  2. header-drawer.js
  3. navigation.js
1 Like

Alternatively, you can add below code before tag in theme.liquid file, it will link parent menu and make it clickable.

1 Like
<script>
  (() => {
    document.querySelectorAll("nav.header__inline-menu details").forEach(details => {
      const summary = details.querySelector("summary");
      const parentLink = details.querySelector("a"); 

      if (!summary || !parentLink) return;

      summary.addEventListener("click", e => {
         if (e.target.closest("svg")) return;

         window.location.href = parentLink.href;
      });
    });
  })();
</script>
1 Like

I had this code in my theme.liquid file, shouid I replace it or place below/above? Before which tag?

<script>
function addAnchorToIcons(){
var $icons = document.querySelectorAll(`.list-social__item a`);

if (!$icons){
return;
}

for (var each of $icons){
each.setAttribute("target", "_blank");
}

}

addAnchorToIcons();
</script>

You can add the given script just below this code you shared.

1 Like

Didn’t work, unfortunately :frowning:

Also, I have something like that in my global.js, but I don’t understand where to put your code or what I should change…

 // Sets inner HTML and reinjects the script tags to allow execution. By default, scripts are disabled when using element.innerHTML.
  static setInnerHTML(element, html) {
    element.innerHTML = html;
    element.querySelectorAll('script').forEach((oldScriptTag) => {
      const newScriptTag = document.createElement('script');
      Array.from(oldScriptTag.attributes).forEach((attribute) => {
        newScriptTag.setAttribute(attribute.name, attribute.value);
      });
      newScriptTag.appendChild(document.createTextNode(oldScriptTag.innerHTML));
      oldScriptTag.parentNode.replaceChild(newScriptTag, oldScriptTag);
    });
  }
}

document.querySelectorAll('[id^="Details-"] summary').forEach((summary) => {
  summary.setAttribute('role', 'button');
  summary.setAttribute('aria-expanded', summary.parentNode.hasAttribute('open'));

  if (summary.nextElementSibling.getAttribute('id')) {
    summary.setAttribute('aria-controls', summary.nextElementSibling.id);
  }

  summary.addEventListener('click', (event) => {
    event.currentTarget.setAttribute('aria-expanded', !event.currentTarget.closest('details').hasAttribute('open'));
  });

  if (summary.closest('header-drawer, menu-drawer')) return;
  summary.parentElement.addEventListener('keyup', onKeyUpEscape);
});

  onSummaryClick(event) {
    const summaryElement = event.currentTarget;
    const detailsElement = summaryElement.parentNode;
    const parentMenuElement = detailsElement.closest('.has-submenu');
    const isOpen = detailsElement.hasAttribute('open');
    const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)');

    function addTrapFocus() {
      trapFocus(summaryElement.nextElementSibling, detailsElement.querySelector('button'));
      summaryElement.nextElementSibling.removeEventListener('transitionend', addTrapFocus);
    }

    if (detailsElement === this.mainDetailsToggle) {
      if (isOpen) event.preventDefault();
      isOpen ? this.closeMenuDrawer(event, summaryElement) : this.openMenuDrawer(summaryElement);

      if (window.matchMedia('(max-width: 990px)')) {
        document.documentElement.style.setProperty('--viewport-height', `${window.innerHeight}px`);
      }
    } else {
      setTimeout(() => {
        detailsElement.classList.add('menu-opening');
        summaryElement.setAttribute('aria-expanded', true);
        parentMenuElement && parentMenuElement.classList.add('submenu-open');
        !reducedMotion || reducedMotion.matches
          ? addTrapFocus()
          : summaryElement.nextElementSibling.addEventListener('transitionend', addTrapFocus);
      }, 100);
    }
  }

  openMenuDrawer(summaryElement) {
    setTimeout(() => {
      this.mainDetailsToggle.classList.add('menu-opening');
    });
    summaryElement.setAttribute('aria-expanded', true);
    trapFocus(this.mainDetailsToggle, summaryElement);
    document.body.classList.add(`overflow-hidden-${this.dataset.breakpoint}`);
  }

  closeMenuDrawer(event, elementToFocus = false) {
    if (event === undefined) return;

    this.mainDetailsToggle.classList.remove('menu-opening');
    this.mainDetailsToggle.querySelectorAll('details').forEach((details) => {
      details.removeAttribute('open');
      details.classList.remove('menu-opening');
    });
    this.mainDetailsToggle.querySelectorAll('.submenu-open').forEach((submenu) => {
      submenu.classList.remove('submenu-open');
    });
    document.body.classList.remove(`overflow-hidden-${this.dataset.breakpoint}`);
    removeTrapFocus(elementToFocus);
    this.closeAnimation(this.mainDetailsToggle);

    if (event instanceof KeyboardEvent) elementToFocus?.setAttribute('aria-expanded', false);
  }

  onFocusOut() {
    setTimeout(() => {
      if (this.mainDetailsToggle.hasAttribute('open') && !this.mainDetailsToggle.contains(document.activeElement))
        this.closeMenuDrawer();
    });
  }

  onCloseButtonClick(event) {
    const detailsElement = event.currentTarget.closest('details');
    this.closeSubmenu(detailsElement);
  }

  closeSubmenu(detailsElement) {
    const parentMenuElement = detailsElement.closest('.submenu-open');
    parentMenuElement && parentMenuElement.classList.remove('submenu-open');
    detailsElement.classList.remove('menu-opening');
    detailsElement.querySelector('summary').setAttribute('aria-expanded', false);
    removeTrapFocus(detailsElement.querySelector('summary'));
    this.closeAnimation(detailsElement);
  }

  closeAnimation(detailsElement) {
    let animationStart;

    const handleAnimation = (time) => {
      if (animationStart === undefined) {
        animationStart = time;
      }

      const elapsedTime = time - animationStart;

      if (elapsedTime < 400) {
        window.requestAnimationFrame(handleAnimation);
      } else {
        detailsElement.removeAttribute('open');
        if (detailsElement.closest('details[open]')) {
          trapFocus(detailsElement.closest('details[open]'), detailsElement.querySelector('summary'));
        }
      }
    };

    window.requestAnimationFrame(handleAnimation);
  }
}

customElements.define('menu-drawer', MenuDrawer);

class HeaderDrawer extends MenuDrawer {
  constructor() {
    super();
  }

  openMenuDrawer(summaryElement) {
    this.header = this.header || document.querySelector('.section-header');
    this.borderOffset =
      this.borderOffset || this.closest('.header-wrapper').classList.contains('header-wrapper--border-bottom') ? 1 : 0;
    document.documentElement.style.setProperty(
      '--header-bottom-position',
      `${parseInt(this.header.getBoundingClientRect().bottom - this.borderOffset)}px`
    );
    this.header.classList.add('menu-open');

    setTimeout(() => {
      this.mainDetailsToggle.classList.add('menu-opening');
    });

    summaryElement.setAttribute('aria-expanded', true);
    window.addEventListener('resize', this.onResize);
    trapFocus(this.mainDetailsToggle, summaryElement);
    document.body.classList.add(`overflow-hidden-${this.dataset.breakpoint}`);
  }

  closeMenuDrawer(event, elementToFocus) {
    if (!elementToFocus) return;
    super.closeMenuDrawer(event, elementToFocus);
    this.header.classList.remove('menu-open');
    window.removeEventListener('resize', this.onResize);
  }

  onResize = () => {
    this.header &&
      document.documentElement.style.setProperty(
        '--header-bottom-position',
        `${parseInt(this.header.getBoundingClientRect().bottom - this.borderOffset)}px`
      );
    document.documentElement.style.setProperty('--viewport-height', `${window.innerHeight}px`);
  };
}

Greatly appreciate your help!

Can you please share the screenshot where you added the below code:

1 Like
<script>
  (() => {
    document.querySelectorAll("nav.header__inline-menu details").forEach(details => {
      const summary = details.querySelector("summary");
      const parentLink = details.querySelector("a"); 

      if (!summary || !parentLink) return;

      summary.addEventListener("click", e => {
         if (e.target.closest("svg")) return;

         window.location.href = parentLink.href;
      });
    });
  })();
</script>
1 Like

Sure! Here it is:

It should work but if it is not working you can add delay to script. Please try below:

1 Like

<script>
  setTimeout(() => {
    (() => {
      document.querySelectorAll("nav.header__inline-menu details").forEach(details => {
        const summary = details.querySelector("summary");
        const parentLink = details.querySelector("a"); 

        if (!summary || !parentLink) return;

        summary.addEventListener("click", e => {
           if (e.target.closest("svg")) return;

          window.location.href = parentLink.href;
        });
      });
    })();
  }, 500); 
</script>

1 Like

or can try below as well:

<script>
(function waitForMenu() {
  const menu = document.querySelector("nav.header__inline-menu");
  if (!menu) {
    // Menu not yet in DOM, try again in 100ms
    setTimeout(waitForMenu, 100);
    return;
  }

  // Menu exists, attach click handlers
  document.querySelectorAll("nav.header__inline-menu details").forEach(details => {
    const summary = details.querySelector("summary");
    const parentLink = details.querySelector("a"); 

    if (!summary || !parentLink) return;

    summary.addEventListener("click", e => {
      // Allow arrow/caret toggle
      if (e.target.closest("svg")) return;

      // Redirect to parent link
      window.location.href = parentLink.href;
    });
  });
})();
</script>

1 Like

I tried both, but still nothing :frowning:

Hey! I believe you still have an access to my website.

Products – DrawWithDi

I have checked the view source but the script is not there. Can you please make sure you added the code at correct file.