babis95
babis95

Reputation: 622

VueJS 3 - <router-link-active> class not applied to routes that start with the same path name

I have created a simple navar where I have 3 links. All links are declared at a ROOT level of the router object. I've added a simple styling targeting the <router-link-active> class where the active link is highlighted on the navbar. This all works fine, switching between links updates the URL, changes the <router-view> as well as applies correct style to the navbar link currently on.

The issue I'm having is that whenever I click on a 4th link which is also declared on the ROOT level of the router object, starting with the same path name as currently active link, the <router-link-active> class disasters. e.g.

{ path: "/link2", component: link2 },
{ path: "/link2/sibling", component: sibling },

My understanding is because the /links2/sibling starts with the same name as /link2, the navbar item that navigates to /link2 should still be have the <router-link-active> class, even when the /link2/sibling is currently active URL.

Codesandbox

App.vue

<template>
  <div>
    <ul class="flex gap-x-5">
      <router-link to="/">
        <li>Link 1</li>
      </router-link>
      <router-link to="/link2">
        <li>Link 2</li>
      </router-link>
      <router-link to="/link3">
        <li>Link 3</li>
      </router-link>
    </ul>
  </div>
  <router-view />
</template>

<script>
export default {
  name: "App",
};
</script>

<style>
a:hover,
a:active,
a.router-link-active {
  color: #f1a80a;
  border-color: #f1a80a;
  background-color: #1a037e;
}
</style>

main.js

import App from "./App.vue";
import router from "./router.js";

const app = createApp(App);

app.use(router);

app.mount("#app");

router.js

import { createRouter, createWebHistory } from "vue-router";
import link1 from "./components/link1.vue";
import link2 from "./components/link2.vue";
import sibling from "./components/sibling.vue";
import link3 from "./components/link3.vue";

const router = createRouter({
  history: createWebHistory(),
  routes: [
    { path: "/", component: link1 },
    { path: "/link2", component: link2 },
    { path: "/link2/sibling", component: sibling },
    { path: "/link3", component: link3 }
  ]
});

export default router;

link1.vue

<template>
  <div>You are inside Link1</div>
</template>

link2.vue

<template>
  <div>
    <router-link to="/link2/sibling">
      You are inside Link 2 (CLICK ME)
    </router-link>
  </div>
</template>

link3.vue

<template>
  <div>You are inside Link 3</div>
</template>

sibling.vue

<template>
  <div>You are inside Link2 sibling</div>
</template>

Upvotes: 7

Views: 3690

Answers (1)

hamid-davodi
hamid-davodi

Reputation: 1966

I think that is the natural behavior that we could expect from routing. when you click on You are inside Link 2 (CLICK ME) inside link2.vue component, the vue-router loads sibling.vue in the router-view part in your App.vue. So there is no You are inside Link 2 (CLICK ME) link in that view to see the router-link-active styles. If you want to see that styles, you must keep your link in the view and don't allow vue-router to disappear that.

For achieving such a goal you can use Nested Routes in vue-router like this. First change your router.js file to something like this:

import { createRouter, createWebHistory } from "vue-router";
import link1 from "./components/link1.vue";
import link2 from "./components/link2.vue";
import sibling from "./components/sibling.vue";
import link3 from "./components/link3.vue";

const router = createRouter({
  history: createWebHistory(),
  routes: [
    { path: "/", component: link1 },
    { 
        path: "/link2",
        component: link2,
        children: [
            {
              path: 'sibling',
              component: sibling
            },
          ]
    },
//    { path: "/link2/sibling", component: sibling
//        
//    },
    { path: "/link3", component: link3 }
  ]
});

export default router;

And then add a <router-view> to your link2.vue file like this:

<template>
  <div>
    <router-link to="/link2/sibling">
      You are inside Link 2 (CLICK ME)
    </router-link>
    <router-view></router-view>
  </div>
</template>

Upvotes: 5

Related Questions