Skip to content
Fix Code Error

Vue js bootstrap add animation while collapse

March 31, 2021 by Code Error
Posted By: Anonymous

I am making a side bar menu with collapse show/hide. With my current css the collapse is not smooth and it seems force full or looks some weird.

I wanted a slide with smooth transition when the item is being closed. But here in my case what’s happening is when some item is already open and next item is clicked(for open). There it looks like toggle is being forcefully and it does not seems smooth collapsing of the list.

What could be the better approach for this please suggest some better ways.

Fiddle Implementation.

I don’t know whether my approach is correct or I am missing something here?

_x000D_

_x000D_

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

_x000D_

.collapse.show {_x000D_
  display: block;_x000D_
}_x000D_
_x000D_
.collapse {_x000D_
  display: none;_x000D_
}_x000D_
_x000D_
.list-unstyled {_x000D_
  padding-left: 0;_x000D_
  list-style: none;_x000D_
}_x000D_
_x000D_
.collapse.list-unstyled {_x000D_
  padding-left: 15px;_x000D_
}_x000D_
_x000D_
nav.side-navbar {_x000D_
  background: #fff;_x000D_
  min-width: 250px;_x000D_
  max-width: 250px;_x000D_
  color: #000;_x000D_
  -webkit-box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1);_x000D_
  box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1);_x000D_
  z-index: 999;_x000D_
}_x000D_
_x000D_
nav.side-navbar ul a:hover {_x000D_
  background: orange;_x000D_
  color: #fff !important;_x000D_
}_x000D_
_x000D_
nav.side-navbar ul a {_x000D_
  padding: 10px 15px;_x000D_
  text-decoration: none;_x000D_
  display: block;_x000D_
  font-weight: 300;_x000D_
  border-left: 4px solid transparent;_x000D_
}

_x000D_

<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet"/>_x000D_
_x000D_
<script src="https://unpkg.com/vue"></script>_x000D_
_x000D_
<div id="app">_x000D_
  <nav class="side-navbar">_x000D_
    <ul class="list-unstyled">_x000D_
      <li>_x000D_
        <a>_x000D_
          <i class="ti-home"></i>Home</a>_x000D_
      </li>_x000D_
      <li v-for="(x, itemIndex) in sideBar" :key="itemIndex">_x000D_
        <a @click="setActiveItemId(itemIndex)">_x000D_
          <i class="fa" :class="x.icon"></i>{{x.name}}_x000D_
        </a>_x000D_
        <ul :id="x.id" class="collapse list-unstyled" :class="{'show':activeItemId === itemIndex  && isActive}">_x000D_
          <li v-for="y in x.children" :key="y.id">_x000D_
            <a>{{y.name}}</a>_x000D_
          </li>_x000D_
        </ul>_x000D_
      </li>_x000D_
    </ul>_x000D_
  </nav>_x000D_
</div>

_x000D_

_x000D_

_x000D_

Solution

You can use Vue’s List Transitions (the <transition-group> tag).

Change the sublist ul to:

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

Mainly instead of hiding the <ul> we are changing the v-for array to/from empty. Notice I also changed the il‘s keys, as you were using an invalid prop.

And add the following CSS for the 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; }
}

Updated JSFiddle here. Demo below.

_x000D_

_x000D_

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

_x000D_

.collapse.show {_x000D_
  display: block;_x000D_
}_x000D_
_x000D_
.collapse {_x000D_
  display: none;_x000D_
}_x000D_
_x000D_
.list-unstyled {_x000D_
  padding-left: 0;_x000D_
  list-style: none;_x000D_
}_x000D_
_x000D_
.collapse.list-unstyled {_x000D_
  padding-left: 15px;_x000D_
}_x000D_
_x000D_
nav.side-navbar {_x000D_
  background: #fff;_x000D_
  min-width: 250px;_x000D_
  max-width: 250px;_x000D_
  color: #000;_x000D_
  -webkit-box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1);_x000D_
  box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1);_x000D_
  z-index: 999;_x000D_
}_x000D_
_x000D_
nav.side-navbar ul a:hover {_x000D_
  background: orange;_x000D_
  color: #fff !important;_x000D_
}_x000D_
_x000D_
nav.side-navbar ul a {_x000D_
  padding: 10px 15px;_x000D_
  text-decoration: none;_x000D_
  display: block;_x000D_
  font-weight: 300;_x000D_
  border-left: 4px solid transparent;_x000D_
}_x000D_
_x000D_
.list-enter {_x000D_
  opacity: 0;_x000D_
}_x000D_
.list-enter-active {_x000D_
  animation: slide-in .5s ease-out forwards;_x000D_
}_x000D_
.list-leave-to, .list-leave-active {_x000D_
  opacity: 0;_x000D_
  animation: slide-out .5s ease-out forwards;_x000D_
}_x000D_
@keyframes slide-in {_x000D_
  from { height: 0; } to { height: 40px; }_x000D_
}_x000D_
@keyframes slide-out {_x000D_
  from { height: 40px; } to { height: 0; }_x000D_
}

_x000D_

<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet" />_x000D_
_x000D_
<script src="https://unpkg.com/vue"></script>_x000D_
_x000D_
<div id="app">_x000D_
  <nav class="side-navbar">_x000D_
    <ul class="list-unstyled">_x000D_
      <li>_x000D_
        <a>_x000D_
          <i class="ti-home"></i>Home</a>_x000D_
      </li>_x000D_
      <li v-for="(x, itemIndex) in sideBar" :key="itemIndex">_x000D_
        <a @click="setActiveItemId(itemIndex)">_x000D_
          <i class="fa" :class="x.icon"></i>{{x.name}}_x000D_
        </a>_x000D_
        <ul :id="x.id" class="collapse list-unstyled show">_x000D_
          <transition-group name="list">_x000D_
            <li v-for="y in (activeItemId === itemIndex  && isActive ? x.children : [])" :key="y.name">_x000D_
              <a>{{y.name}}</a>_x000D_
            </li>_x000D_
          </transition-group>_x000D_
        </ul>_x000D_
      </li>_x000D_
    </ul>_x000D_
  </nav>_x000D_
</div>

_x000D_

_x000D_

_x000D_

Answered By: Anonymous

Related Articles

  • Slide transition with vue isn't working properly
  • React Multi-level push menu SCSS Back button not working
  • Javascript text animation not triggering
  • After a little scroll, the sticky navbar just is not fixed…
  • Why are CSS keyframe animations broken in Vue components…
  • Having trouble with my nav bar/header, It used to work but…
  • Animating Elements in One by One
  • center images with each other in logo carousel
  • Android Layout Animations from bottom to top and top to…
  • useEffect Error: Minified React error #321 (GTM…

Disclaimer: This content is shared under creative common license cc-by-sa 3.0. It is generated from StackExchange Website Network.

Post navigation

Previous Post:

Select Component Vue JS – Default Select Value

Next Post:

Passing on:click event into dynamically created

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

  • Get code errors & solutions at akashmittal.com
© 2022 Fix Code Error