Search code examples
cssvuetify.jsnavigation-drawer

Vuetify navigation drawer keep list item colored on click


I have created a navigation drawer but cannot achieve to keep background on item click.

what i have for now is custom scoped css for the list that looks like.

enter image description here

What i want to achieve is that the background green color remains on click. and change list item backround according to whereever i click between default background and my style.

For now my code looks like.

<v-navigation-drawer
          v-model="drawer"
          :mini-variant.sync="mini"
          height="100vh"
          permanent
          color="blue-grey darken-4"
        >
          <v-list-item class="px-2">
            <v-list-item-avatar>
              <v-img src="https://randomuser.me/api/portraits/men/85.jpg" />
            </v-list-item-avatar>

            <v-list-item-title class="ListItemClass">
              John Leider
            </v-list-item-title>

            <v-btn
              icon
              @click.stop="mini = !mini"
              color="blue-grey lighten-5"
            >
              <v-icon>mdi-chevron-left</v-icon>
            </v-btn>
          </v-list-item>

          <v-list-item class="mb-1 px-2">
            <v-list-item-icon>
              <v-btn
                icon
                @click.stop="mini = !mini"
                color="blue-grey lighten-5"
              >
                <v-icon>mdi-arrow-expand-horizontal</v-icon>
              </v-btn>
            </v-list-item-icon>
          </v-list-item>
          <div
            id="divider"
            style="background-color:#f5f5f5; height: 2px; width:80%;margin: 0 auto;;"
          />

          <v-list dense>
            <v-list-item
              class="SelectedTile"
              v-for="item in items"
              :key="item.title"
              link
            >
              <v-list-item-icon>
                <v-icon color="blue-grey lighten-5">
                  {{ item.icon }}
                </v-icon>
              </v-list-item-icon>

              <v-list-item-content color="blue-grey lighten-5">
                <v-list-item-title class="ListItemClass">
                  {{ item.title }}
                </v-list-item-title>
              </v-list-item-content>
            </v-list-item>
          </v-list>
        </v-navigation-drawer>

And my style

<style scoped>
.ListItemClass {
  color: #f5f5f5;
}
.SelectedTile:hover {
    border-radius: 4px;
    background: #455A64
}
.SelectedTile:active {
    border-radius: 4px;
    background: rgba(10, 204, 117, 0.19)
}
</style>

I connot figure out how to do it.

Thanks for the help


Solution

  • If you are creating v-navigation-drawer for the whole app, it would be better if you will change something in your template.

    I hope you are using vue-router to navigate between pages.

    Your App.vue should look like this:

    <template>
      <v-app>
        <v-navigation-drawer
          app
          ...another props
        >
          ...navigation-drawer internal data
        </v-navigation-drawer>
        
        <v-main>
          <v-container fluid>
            <router-view></router-view>
          </v-container>
        </v-main>
      </v-app>
    </template>
    

    With a template like this you can use an active-class prop inside your v-list-item component this way:

    ...
    <v-list dense>
      <v-list-item
        class="SelectedTile"
        active-class="SelectedTile-active"
        v-for="item in items"
        :key="item.title"
        :to="item.path"
        link
      >
        <v-list-item-icon>
          <v-icon color="blue-grey lighten-5">
            {{ item.icon }}
          </v-icon>
        </v-list-item-icon>
    
        <v-list-item-content color="blue-grey lighten-5">
          <v-list-item-title class="ListItemClass">
            {{ item.title }}
          </v-list-item-title>
        </v-list-item-content>
      </v-list-item>
    </v-list>
    ...
    <script>
    export default {
      ...
      data() {
        return {
          ...
          items: [
            { title: "First", icon: "mdi-home", path: "/first" },
            { title: "Second", icon: "mdi-send", path: "/second" },
            { title: "Third", icon: "mdi-lock", path: "/third" },
          ],
        };
      },
    };
    </script>
    
    <style scoped>
    .ListItemClass {
      color: #f5f5f5;
    }
    
    .SelectedTile:hover {
        border-radius: 4px;
        background: #455A64
    }
    
    .SelectedTile-active {
      border-radius: 4px;
      background: rgba(10, 204, 117, 0.19)
    }
    </style>
    

    Check this demo at CodeSandbox.


    If for some reason you cannot use the first method, try this:

    To create a group of selectable v-list-item's you can wrap it into v-list-item-group component:

    ...
    <v-list dense>
      <v-list-item-group
        v-model="selectedItem"
        active-class="SelectedTile-active"
        mandatory
      >
        <v-list-item
          class="SelectedTile"
          v-for="item in items"
          :key="item.title"
          link
        >
          <v-list-item-icon>
            <v-icon color="blue-grey lighten-5">
              {{ item.icon }}
            </v-icon>
          </v-list-item-icon>
    
          <v-list-item-content color="blue-grey lighten-5">
            <v-list-item-title class="ListItemClass">
              {{ item.title }}
            </v-list-item-title>
          </v-list-item-content>
        </v-list-item>
      </v-list-item-group>
    </v-list>
    ...
    data: () => ({
      ...
      selectedItem: 0,
    })
    ...
    <style scoped>
    .ListItemClass {
      color: #f5f5f5;
    }
    
    .SelectedTile:hover {
        border-radius: 4px;
        background: #455A64
    }
    
    .SelectedTile-active {
      border-radius: 4px;
      background: rgba(10, 204, 117, 0.19)
    }
    </style>
    

    But as you can see, if you are using mandatory prop in v-list-item-group component, at least one item should always be selected.