nuxt / nuxt/ui

Nuxt 3/Nuxt UI UNavigationMenu won’t highlight hash‐based section on page reload

Open
#4,416 8 comments 0 reactions 1 assignee View on GitHub

@J-Michalek is already working on this.

Since Jul 2, 2025.

triage
Dominant language
TypeScript
Stars
6.9k
Forks
1.1k
Avg merge
1d 7h
Merged PRs (30d)
57

Description

Environment

"nuxt": "^3.17.5",
"@nuxt/ui": "^3.1.3",

Is this bug related to Nuxt or Vue?

Nuxt

Version

3.1.3

Reproduction

Following is my components/AppHeader.vue:

<template>
  <header class="bg-white sticky top-0 z-50">
    <nav class="hidden lg:flex flex-1 justify-center">
      <UNavigationMenu
        v-model="activeSection"
        :items="navItems"
        class="space-x-2"
        highlight
        highlight-color="primary"
      >
        <template #item="{ item, active }">
          <ULink
            as-child
            :to="{ path: '', hash: `#${item.to}` }"
            exact-hash
            class="px-4 py-2 rounded-md transition"
            aria-label="Go to {{ item.label }}"
          >
            <span class="inline-flex items-center">
              <UIcon v-if="item.icon" :name="item.icon" class="size-5 mr-2" />
              <span>{{ item.label }}</span>
            </span>
          </ULink>
        </template>
      </UNavigationMenu>
    </nav>
  </header>
</template>

<script setup lang="ts">
import { ref, watch, onMounted } from "vue";
import { useRoute } from "vue-router";
import type { NavigationMenuItem } from "@nuxt/ui";

const route = useRoute();
const activeSection = ref("");

// Define your nav data (to = hash without leading '#')
const navItems = ref<NavigationMenuItem[]>([
  { label: "Home", icon: "i-lucide-home", value: "", to: "" },
  {
    label: "About Us",
    icon: "i-lucide-user-circle",
    value: "about",
    to: "about",
  },
  {
    label: "Products",
    icon: "i-lucide-package",
    value: "products",
    to: "products",
  },
  {
    label: "Technologies",
    icon: "i-lucide-cpu",
    value: "technologies",
    to: "technologies",
  },
  {
    label: "News",
    icon: "i-lucide-newspaper",
    value: "news",
    to: "news",
  },
]);

// On load, seed activeSection from the current hash
onMounted(() => {
  activeSection.value = route.hash.replace(/^#/, "");
});

// Update when the hash changes
watch(
  () => route.hash,
  (h) => {
    activeSection.value = h.replace(/^#/, "");
  }
);
</script>
Description

I’m using the Nuxt UI <UNavigationMenu> component in my Nuxt 3 app to render a header nav that scrolls to sections via hash links within my pages/index.vue (#about, #products, #news, etc.). Clicking works fine, and the correct menu item highlights and scrolls to that section.

However, if I reload the page while viewing, for example,/#products or any other section like #news, #about, etc., the page scrolls to the respective products/news/about section, but the navigation menu always highlights “Home” (the first item) instead of Products/News/About.

How can I get <UNavigationMenu> to pick up the current route.hash on load so that the correct item is active?

Following is the documentation I am refeering to:
API: https://ui.nuxt.com/components/navigation-menu

Additional context

No response

Logs

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.