Expanding up or down This is a jQuery function that controls a &lt;div&gt; to expand up or expand down. I am trying to simplify and optimize these lines of codes.

Scenerio

By default, it does not have any classes in &lt;div class="title-wrapper"&gt;.

When I clicked on &lt;div class="title-wrapper"&gt;, it adds .expand-up into this &lt;div&gt; if there .expand-up class. When I clicked on &lt;div class="title-wrapper"&gt; it should remove .expand-up from &lt;div&gt; and only remove if there is .expand-down.



$(document).ready(function() {
  $('.title-wrapper').click(function() {
    $(this).parent().toggleClass('active').delay('1500').promise().done(function() {
      var filterSearch = $(this).children('.title-wrapper');
      // Check if have expand-up classes
      if (filterSearch.hasClass('expand-up')) {
        filterSearch.removeClass('expand-up');
        filterSearch.addClass('expand-down');
      } else {
        // Remove expand down if the class is existed
        if (filterSearch.hasClass('expand-down')) {
          filterSearch.removeClass('expand-down');
        }
        filterSearch.addClass('expand-up');
      }
    });
  });
});
body {
  font-size: 62.5%;
  font-family: 'Roboto', sans-serif;
  color: #FFF;
}
.filter-search {
  background-color: #a78464;
}
.filter-search .wrapper {
  width: 100%;
  text-align: center;
  height: 10em;
  transition: height linear 1s;
}
.filter-search .wrapper .title-wrapper {
  display: inline-block;
}
.filter-search .wrapper .title-wrapper h2 {
  font-size: 3em;
  margin-bottom: 0;
}
.filter-search .wrapper .title-wrapper span {
  font-size: 1.4em;
  display: block;
  text-transform: uppercase;
  margin-bottom: 2em;
}
.filter-search .wrapper.active {
  height: 15em;
  transition: height linear 1s;
}
.filter-search .expand-up {
  -webkit-animation: moveUp ease-in 1;
  animation: moveUp ease-in 1;
  animation-fill-mode: forwards;
  animation-duration: .5s;
}
.filter-search .expand-down,
.filter-search .expand-up {
  -webkit-animation-fill-mode: forwards;
  -webkit-animation-duration: .5s;
}
.filter-search .expand-down {
  -webkit-animation: moveDown ease-out 1;
  animation: moveDown ease-out 1;
  animation-fill-mode: forwards;
  animation-duration: .5s;
}
@-webkit-keyframes moveUp {
  0% {
    margin-top: 0;
  }
  to {
    margin-top: -1em;
  }
  ;
}
@keyframes moveUp {
  0% {
    margin-top: 0;
  }
  to {
    margin-top: -1em;
  }
  ;
}
@-webkit-keyframes moveDown {
  0% {
    margin-top: -1em;
  }
  to {
    margin-top: 0;
  }
  ;
}
@keyframes moveDown {
  0% {
    margin-top: -1em;
  }
  to {
    margin-top: 0;
  }
  ;
}
&lt;link href='https://fonts.googleapis.com/css?family=Open+Sans:400,300,300italic,400italic,600,600italic,700,700italic,800,800italic' rel='stylesheet' type='text/css'&gt;
&lt;link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"&gt;
&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"&gt;&lt;/script&gt;

&lt;!-- Coding Start Here --&gt;
&lt;section id="filter-search" class="filter-search"&gt;
  &lt;div class="wrapper"&gt;
    &lt;i class="material-icons"&gt;search&lt;/i&gt;
    &lt;div class="title-wrapper"&gt;
      &lt;h2&gt;Filter Search&lt;/h2&gt;
      &lt;span&gt;Click to expand&lt;/span&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/section&gt;
As there is only two states, up and down, we can leave out .expand-up and let it be the default state. I refactored the css and js code to just add and remove the expand-down class, for the .css file,

body {
    font-size: 62.5%;
    font-family: 'Roboto', sans-serif;
    color: #FFF;
}
.filter-search {
    background-color: #a78464;
}
.filter-search .wrapper {
    width: 100%;
    text-align: center;
    height: 10em;
    transition: height linear 1s;
}
.filter-search .wrapper .title-wrapper {
    display: inline-block;
    animation-fill-mode: forwards;
    animation-duration: .5s;
    -webkit-animation-fill-mode: forwards;
    -webkit-animation-duration: .5s;
}
.filter-search .wrapper .title-wrapper.expand-down {
    -webkit-animation: moveDown ease-out 1;
    animation: moveDown ease-out 1;
}
.filter-search .wrapper .title-wrapper h2 {
    font-size: 3em;
    margin-bottom: 0;
}
.filter-search .wrapper .title-wrapper span {
    font-size: 1.4em;
    display: block;
    text-transform: uppercase;
    margin-bottom: 2em;
}
.filter-search .wrapper.active {
    height: 15em;
    transition: height linear 1s;
}
@-webkit-keyframes moveUp {
    0% {
        margin-top: 0;
    }
    to {
        margin-top: -1em;
    }
}
@keyframes moveUp {
    0% {
        margin-top: 0;
    }
    to {
        margin-top: -1em;
    }
}
@-webkit-keyframes moveDown {
    0% {
        margin-top: -1em;
    }
    to {
        margin-top: 0;
    }
}
@keyframes moveDown {
    0% {
        margin-top: -1em;
    }
    to {
        margin-top: 0;
    }
}


and for the .js file I changed click() to on(), in case the element will be added dynamically, click() would not work. Also assigning variable filterSearch earlier in the function, there should be no need to find the children with each click,

$(document).ready(function() {
    $('#filter-search').on('click', '.title-wrapper', function() {
        var filterSearch = $(this);

        filterSearch.parent().toggleClass('active').delay('1500').promise().done(function() {
            if (filterSearch.hasClass('expand-down')) {
                filterSearch.removeClass('expand-down');
            } else {
                filterSearch.addClass('expand-down');
            }
        });
    });
});