138

My page currently has Navigation.vue component. I want to make the each navigation hover and active. The hover works but active doesn't.

This is how Navigation.vue file looks like :

<template>
  <div>
    <nav class="navbar navbar-expand-lg fixed-top row">
      <router-link tag="li" class="col" class-active="active" to="/" exact>TIME</router-link>
      <router-link tag="li" class="col" class-active="active" to="/CNN" exact>CNN</router-link>
      <router-link tag="li" class="col" class-active="active" to="/TechCrunch" exact>TechCrunch</router-link>
      <router-link tag="li" class="col" class-active="active" to="/BBCSport" exact>BBC Sport</router-link>
    </nav>
  </div>
</template>

And the following is the style.

<style>
nav li:hover,
nav li:active {
  background-color: indianred;
  cursor: pointer;
}
</style>

This is how hover looks like now and expected exactly same on active.

This is how hover looks like now and expected exactly same on active.

I would appreciate if you give me an advice for styling router-link active works. Thanks.

Penny Liu
  • 15,447
  • 5
  • 79
  • 98
doobean
  • 1,929
  • 4
  • 19
  • 27
  • https://router.vuejs.org/en/api/options.html#linkexactactiveclass – Bert Sep 06 '17 at 19:49
  • Hi @Bert, thanks for your comment. I've tried instead of , but doesn't work yet. – doobean Sep 06 '17 at 20:02
  • That's not where you specify it. You specify `linkExactActiveClass` as a property of your router (where you add the `routes`). – Bert Sep 06 '17 at 20:04
  • TY @KateYeeumLee for this question. Was just getting ready to build something like this and come to realize that it should be its own component - not part of TheHeader.vue :) – CodeFinity Aug 05 '18 at 16:55

7 Answers7

308

The :active pseudo-class is not the same as adding a class to style the element.

The :active CSS pseudo-class represents an element (such as a button) that is being activated by the user. When using a mouse, "activation" typically starts when the mouse button is pressed down and ends when it is released.

What we are looking for is a class, such as .active, which we can use to style the navigation item.

For a clearer example of the difference between :active and .active see the following snippet:

li:active {
  background-color: #35495E;
}

li.active {
  background-color: #41B883;
}
<ul>
  <li>:active (pseudo-class) - Click me!</li>
  <li class="active">.active (class)</li>
</ul>

Vue-Router

vue-router automatically applies two active classes, .router-link-active and .router-link-exact-active, to the <router-link> component.


router-link-active

This class is applied automatically to the <router-link> component when its target route is matched.

The way this works is by using an inclusive match behavior. For example, <router-link to="/foo"> will get this class applied as long as the current path starts with /foo/ or is /foo.

So, if we had <router-link to="/foo"> and <router-link to="/foo/bar">, both components would get the router-link-active class when the path is /foo/bar.


router-link-exact-active

This class is applied automatically to the <router-link> component when its target route is an exact match. Take into consideration that both classes, router-link-active and router-link-exact-active, will be applied to the component in this case.

Using the same example, if we had <router-link to="/foo"> and <router-link to="/foo/bar">, the router-link-exact-activeclass would only be applied to <router-link to="/foo/bar"> when the path is /foo/bar.


The exact prop

Lets say we have <router-link to="/">, what will happen is that this component will be active for every route. This may not be something that we want, so we can use the exact prop like so: <router-link to="/" exact>. Now the component will only get the active class applied when it is an exact match at /.


CSS

We can use these classes to style our element, like so:

 nav li:hover,
 nav li.router-link-active,
 nav li.router-link-exact-active {
   background-color: indianred;
   cursor: pointer;
 }

The <router-link> tag was changed using the tag prop, <router-link tag="li" />.


Change default classes globally

If we wish to change the default classes provided by vue-router globally, we can do so by passing some options to the vue-router instance like so:

const router = new VueRouter({
  routes,
  linkActiveClass: "active",
  linkExactActiveClass: "exact-active",
})

Change default classes per component instance (<router-link>)

If instead we want to change the default classes per <router-link> and not globally, we can do so by using the active-class and exact-active-class attributes like so:

<router-link to="/foo" active-class="active">foo</router-link>

<router-link to="/bar" exact-active-class="exact-active">bar</router-link>

v-slot API

Vue Router 3.1.0+ offers low level customization through a scoped slot. This comes handy when we wish to style the wrapper element, like a list element <li>, but still keep the navigation logic in the anchor element <a>.

<router-link
  to="/foo"
  v-slot="{ href, route, navigate, isActive, isExactActive }"
>
  <li
    :class="[isActive && 'router-link-active', isExactActive && 'router-link-exact-active']"
  >
    <a :href="href" @click="navigate">{{ route.fullPath }}</a>
  </li>
</router-link>
li ki
  • 342
  • 3
  • 11
Ricky Ruiz
  • 25,455
  • 6
  • 44
  • 53
  • Sorry but the names are not that self-explanatory to me :) What about normal links that aren't active or "exact"? In my case, my normal links get styled in an unwanted way by Vue. Changing the active or exact styles has no effect. – Kokodoko Feb 03 '18 at 21:38
  • 7
    This is answer deserve an award for taking time to explain – jovialcore Dec 23 '21 at 13:45
  • I want to set only one breadcrumb link to active, for the current route, and just this worked: **About – shasi kanth Apr 06 '23 at 05:50
  • any idea why scroll-click (middle click) stops working as soon as you access v-slot on router-link by v-slot="{ isActive }"? The DOM element is being changed to span from anchor. Why is it so? Setting tag="a" doesn't change anything – user2923339 Apr 24 '23 at 08:52
39

https://router.vuejs.org/en/api/router-link.html add attribute active-class="active" eg:

<ul class="nav navbar-nav">
    <router-link tag="li" active-class="active" to="/" exact><a>Home</a></router-link>
    <router-link tag="li" active-class="active" to="/about"><a>About</a></router-link>
    <router-link tag="li" active-class="active" to="/permission-list"><a>Permisison</a></router-link>
</ul>
Vi Quang Hòa
  • 537
  • 4
  • 6
35

When you are creating the router, you can specify the linkExactActiveClass as a property to set the class that will be used for the active router link.

const routes = [
  { path: '/foo', component: Foo },
  { path: '/bar', component: Bar }
]

const router = new VueRouter({
  routes,
  linkActiveClass: "active", // active class for non-exact links.
  linkExactActiveClass: "active" // active class for *exact* links.
})

This is documented here.

Bert
  • 80,741
  • 17
  • 199
  • 164
  • This works well, but in my app, it's always considering `/` as active (since URLs like `/about` contain it). – Scribblemacher Apr 12 '18 at 23:53
  • 2
    @Scribblemacher if I understand correctly, just remove the linkActiveClass https://codepen.io/Kradek/pen/zWQKYp – Bert Apr 13 '18 at 00:50
7

As mentioned above by @Ricky vue-router automatically applies two active classes, .router-link-active and .router-link-exact-active, to the <router-link> component.

So, to change active link css use:

.router-link-exact-active {
  //your desired design when link is clicked
  font-weight: 700;
}
Penny Liu
  • 15,447
  • 5
  • 79
  • 98
Dilip Gautam
  • 114
  • 1
  • 4
  • 1
    how to make this work if your design needs a different colour per menu item when its active ? – GY22 Apr 29 '20 at 23:41
6

Just add to @Bert's solution to make it more clear:

    const routes = [
  { path: '/foo', component: Foo },
  { path: '/bar', component: Bar }
]

const router = new VueRouter({
  routes,
  linkExactActiveClass: "active" // active class for *exact* links.
})

As one can see, this line should be removed:

linkActiveClass: "active", // active class for non-exact links.

this way, ONLY the current link is hi-lighted. This should apply to most of the cases.

David

us_david
  • 4,431
  • 35
  • 29
3

Let's make things simple, you don't need to read the document about a "custom tag" (as a 16 years web developer, I have enough this kind of tags, such as in struts, webwork, jsp, rails and now it's vuejs)

just press F12, and you will see the source code like:

<div>
  <a href="#/topologies" class="luelue">page1</a> 
  <a href="#/" aria-current="page" class="router-link-exact-active router-link-active">page2</a> 
  <a href="#/databases" class="">page3</a>
</div>

so just add styles for the .router-link-active or .router-link-exact-active

If you want more details, check the router-link api: https://router.vuejs.org/guide/#router-link

Penny Liu
  • 15,447
  • 5
  • 79
  • 98
Siwei
  • 19,858
  • 7
  • 75
  • 95
0

For anyone using Tailwind, you can work with the active class and exact active classes in this way:

<router-link
    :active-class="'bg-gray-100 bg-opacity-50 hover:bg-gray-200'"
    :exact-active-class="'bg-red-100 bg-opacity-50 hover:bg-red-200'"
    class="bg-gray"
>
    ...
</router-link>

Using the above, the default class is bg-gray. When the link is clicked, it will have the exact-active-class. If a child route is clicked, the element will take on the active class.

Damon
  • 4,151
  • 13
  • 52
  • 108