Enhance the collapsible feature in Vue.js by integrating Bootstrap and anim

In the process of creating a side bar menu with collapse show/hide functionality, I am encountering some issues. The current CSS implementation is making the collapse action appear abrupt and unnatural.

I am looking to achieve a smooth sliding transition when an item is being closed. However, the problem arises when one item is already open and another item is clicked to open. It seems like the toggle effect is too forced and does not provide a smooth collapsing effect for the list.

Any suggestions on a better approach to achieve this desired smooth transition?

View Fiddle Implementation.

I am uncertain whether my current approach is correct or if there is something missing in my code?

new Vue({
  el: '#app',
  methods: {
    setActiveItemId(itemIndex) {
      if (itemIndex === this.activeItemId) {
        this.activeItemId = ''
        return
      }
      this.activeItemId = itemIndex
    }
  },
  data() {
    return {
      message: 'Hello Vue.js!',
      activeItemId: '',
      sideBar: [{
          name: "Dashboard",
          url: "/dashboard",
          icon: "ti-world",
          children: [{
              name: "Buttons",
              url: "/components/buttons",
              icon: "fa-book",
            },
            {
              name: "Social Buttons",
              url: "/components/social-buttons",
              icon: "icon-puzzle",
            }
          ]
        },
        {
          name: "Components",
          url: "/components",
          icon: "ti-pencil-alt",
          children: [{
              name: "Buttons",
              url: "/components/buttons",
              icon: "fa-book",
            },
            {
              name: "Social Buttons",
              url: "/components/social-buttons",
              icon: "icon-puzzle",
            }
          ]
        },
        {
          name: "Validation",
          url: "/components",
          icon: "ti-pencil-alt",
          children: [{
              name: "Buttons",
              url: "/components/buttons",
              icon: "fa-book",
            },
            {
              name: "Social Buttons",
              url: "/components/social-buttons",
              icon: "icon-puzzle",
            }
          ]
        }
      ]
    }
  },
  computed: {
    isActive() {
      return this.activeItemId !== ''
    }
  }
})
.collapse.show {
  display: block;
}

.collapse {
  display: none;
}

.list-unstyled {
  padding-left: 0;
  list-style: none;
}

.collapse.list-unstyled {
  padding-left: 15px;
}

nav.side-navbar {
  background: #fff;
  min-width: 250px;
  max-width: 250px;
  color: #000;
  -webkit-box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1);
  box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1);
  z-index: 999;
}

nav.side-navbar ul a:hover {
  background: orange;
  color: #fff !important;
}

nav.side-navbar ul a {
  padding: 10px 15px;
  text-decoration: none;
  display: block;
  font-weight: 300;
  border-left: 4px solid transparent;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet"/>

<script src="https://unpkg.com/vue"></script>

<div id="app">
  <nav class="side-navbar">
    <ul class="list-unstyled">
      <li>
        <a>
          <i class="ti-home"></i>Home</a>
      </li>
      <li v-for="(x, itemIndex) in sideBar" :key="itemIndex">
        <a @click="setActiveItemId(itemIndex)">
          <i class="fa" :class="x.icon"></i>{{x.name}}
        </a>
        <ul :id="x.id" class="collapse list-unstyled" :class="{'show':activeItemId === itemIndex  && isActive}">
          <li v-for="y in x.children" :key="y.id">
            <a>{{y.name}}</a>
          </li>
        </ul>
      </li>
    </ul>
  </nav>
</div>

Answer №1

To implement transitions in Vue, you can utilize Vue's List Transitions feature (using the <transition-group> tag).

Modify the nested list ul as follows:

<ul :id="x.id" class="collapse list-unstyled show">
  <transition-group name="list">
    <li v-for="y in (activeItemId === itemIndex  && isActive ? x.children : [])" :key="y.name">
      <a>{{y.name}}</a>
    </li>
  </transition-group>
</ul>

Essentially, instead of simply hiding the <ul>, we are dynamically switching the v-for array from empty to filled based on conditions. Note that I have also corrected the keys for y.name since an incorrect prop was being used.

Additionally, apply the following CSS code for smoother transitions:

.list-enter {
  opacity: 0;
}
.list-enter-active {
  animation: slide-in .5s ease-out forwards;
}
.list-leave-to, .list-leave-active {
  opacity: 0;
  animation: slide-out .5s ease-out forwards;
}
@keyframes slide-in {
  from { height: 0; } to { height: 40px; }
}
@keyframes slide-out {
  from { height: 40px; } to { height: 0; }
}

For a demo and updated reference, check out this JSFiddle link. See the demo below.

<!-- JavaScript code here -->
<!-- CSS code here -->
<!-- HTML code here -->

Answer №2

If you're looking for a simpler workaround, consider including the following CSS snippet in your stylesheet.

.display {
  animation: width 0.5s, height 0.5s, transform 0.5s;
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for adding extra spacing between icon and text field using Vuetify

The code snippet below is used for the username section: <v-text-field prepend-icon="fas fa-user" height="60px" placeholder="Username" outlined ></v-text-field> Is there a way to add space between the user ...

How to trigger an event with multiple parameters up several levels using Vue 3?

Important Note: While this question may seem repetitive to some, I have not been able to find a suitable solution for Vue 3 that involves passing events with parameters through multiple levels. Please correct me if I am mistaken. A Clarification: Despite ...

What is the process for generating a tree structure from an HTML element?

This particular element is found within my Vue2 application: <div class="child-elements-container draggable-container"> <div> <div entity-type="entitytype1" type="elementType" id="2" class= ...

Is it true that eliminating white spaces can enhance a website's loading speed?

I'm curious about something. Can removing white space actually make a website load faster? For instance, take a look at the following CSS snippet - body{ overflow-wrap:break-word; word-break:break-word; word-wrap:break-word } .hidden{ display:none } . ...

Is it possible to conceal the source code within the dist js file using Vue JS?

I am looking to create a detailed logging page that showcases the logs without revealing the specific type of logging. I want to prevent users from accessing the minified vue JS script and easily reading the logged information. Is there a way to implemen ...

Avoid floating right elements all the way up if there are already elements floating left

I am struggling to position block 5 next to block 3 on larger screens, while maintaining the desired arrangement on smaller viewports. The blocks do not have fixed heights in my setup. You can see my codepen for a better understanding of what I'm try ...

Quick way to include id="" and class="" attributes to HTML elements using Sublime Text 2

Is there a way to configure Sublime Text 2 where inputting a . (dot) automatically generates class=" " and adding a # (hash) creates id=" " while typing an HTML opening tag? ...

Searching in Vue based on the selected option is only possible by the selected criteria and not by id, regardless of the

#1 Even if chosen, cannot search by id. The 'name' condition in the loop works well but I am unable to correctly search by id (returns nothing). #2 When selecting an option from the dropdown menu, it only displays until I start typing. I would l ...

Why do style assignments lose their motion when executed right after being made?

If you take a look at this specific fiddle in Webkit, you will see exactly what I am referring to. Is there a way to define the style of an element when it is first specified, and then its final state? I would like to be able to fully define a single-ste ...

Executing Javascript to populate a div element with content based on its CSS class

Is there a way to isolate my View (HTML & CSS files) within a controller like JavascriptCode/AJAX, so that upon page load, only the controller binds the data to a specific element such as a DIV based on its class? Do you think this is achievable? If so, ...

Using canvas elements to position divs in three.js

I am currently in the process of developing a custom animation player using Three.js for rendering objects, which is functioning perfectly. However, I am encountering difficulty when trying to incorporate control options at the bottom of the player (such a ...

Adding multiple elements with varying content to a separate division

I am attempting to combine two div elements into a single div, but I'm encountering difficulties. Despite thoroughly examining my code, everything appears to be correct. Here's what I've tried so far. To assist me in achieving this, I am ut ...

Managing the height of a TextArea within a Flexbox environment

After exploring various methods for achieving auto-height in a textarea, I decided to go with the contenteditable approach as it seemed cleaner to me. However, while it worked perfectly on its own, it failed when placed within flexbox containers. I experi ...

Vue.js integration causes Bootstrap modals to stop functioning properly

Recently, my coworker integrated Vue.js into our codebase which still heavily relies on jQuery. A major issue we encountered was that all the modals in our application would not display when triggered using JavaScript. What made things even more puzzling ...

tips for expanding the size of your images

Hey there, I'm looking for some help with the code below. I need to increase the width of the images and remove the border of the slider div which is currently showing a white border that I want to get rid of. I am using JavaScript to display the imag ...

What steps should we take to ensure that the container beside the fixed left navigation bar is responsive?

Currently, I am working on creating a user interface that features a fixed navigation bar on the left hand side and a responsive content window. Here is what I have implemented so far: <div style="width: 15%; float: left; display: inline;"> <na ...

Creating a variable by utilizing $index values within two nested v-for loops

For my project, I am attempting to organize the days of a month into a table using 2 v-for loops. To simplify my code, I am considering creating a t_index variable that would be equal to ((r_index - 1) * 7 + c_index) - 2, but I am unsure how to implement ...

Is it advantageous to incorporate jwt into my Vue application alongside Vuex for added benefits?

As I develop a Vue application with pure PHP for the backend, I considered implementing jwt (JSON Web Tokens) for authentication. After referring to this article and this one, I successfully integrated jwt into both the front-end (Vue) and back-end (PHP) o ...

Assistance with HTML and CSS to position an image in the corner

I need assistance with positioning a corner image on top of another image. I want the span, which has a small background image, to be in the top left corner of the main image. Below is my code: <div id="wrapkon"> <span style="width: 4px; height: ...

Unable to display background image and color on Internet Explorer

The background beneath the slider and footer appears normal in most browsers, but there seems to be an issue with Internet Explorer. Check it out at this link: Do you have any suggestions on how to fix this? ...