Search code examples
vue.jsvue-routerrouterlink

How to VueJS router-link active style


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.


Solution

  • 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>