title: Plain javascript trigger css fade out, ajax load content, fade in using CSS
body: <p>Trying to figure out how to do this with plain javascript and css, below is code working with jquery.</p>
  
  <p>In this example a user clicks a link, the script checks to see if there is content in a div, if there is, it fades out the content, then loads by ajax the new content and fades it in.</p>
  
  <p>I know I can toggle a css class, but wondering how to go about using a <strong>callback</strong> to see when the css animation has completed to be able to fire the ajax request and then fade in.</p>
  
  <pre><code>&lt;section&gt;
      &lt;a href="#" data-file="data1"&gt;Load data 1&lt;/a&gt;
      &lt;a href="#" data-file="data2"&gt;Load data 2&lt;/a&gt;
      &lt;div id="content"&gt;&lt;/div&gt;
  &lt;/section&gt;
  
  $(document).ready(function(){
      $('body').on('click','a',function(event){
          event.preventDefault();
          var datafile = $(this).data('file');
          console.log(datafile);
          if($('#content').html().length){
              $('#content').fadeOut(700,function(){
                  $('#content').load(datafile + '.php').hide().fadeIn(700);
                  console.log('has content, fadeout then load fadein ' + datafile);
              })
          } else {
              $('#content').load(datafile + '.php').hide().fadeIn(700);
              console.log('no content, load fadein ' + datafile);
          }
      });
  });
  </code></pre>
  
  <p>contents of <strong>data1.php</strong> and <strong>data2.php</strong> are filled with lorem ipsum just for testing purposes, in production they would be interface screens for a cms.</p>
  
  <p>here is a jsfiddle
  <a href="https://jsfiddle.net/nomadwebdesign/cfvd6uk4/" rel="nofollow noreferrer">https://jsfiddle.net/nomadwebdesign/cfvd6uk4/</a></p>
  
  <p>Looking at Dan Dascalescu's answer and how to expand upon this <a href="https://stackoverflow.com/questions/6121203/how-to-do-fade-in-and-fade-out-with-javascript-and-css">How to do fade-in and fade-out with JavaScript and CSS</a></p>
  
  <p>I've also been trying to use the on('transitionend') event listener, however it goes into a loop because after loading by ajax I remove the css class causing the transition again.</p>
  
  <p>I am able to do this by using setTimeout and matching the transition duration however this seems flaky.</p>
  
  <p>At this point I would just like to know how to do this with <strong>jQuery</strong> and <strong>CSS</strong> without using <strong>fadeIn()</strong> and <strong>fadeOut()</strong></p>
  
  <p>the sequence is
  click -> fade out previous content -> fade in ajax loaded content</p>
  
  <p><strong>UPDATE</strong>
  Here is a working solution using <strong>jQuery without fadeIn() or fadeOut()</strong> but with CSS opacity transition</p>
  
  <pre><code>&lt;section id="section2"&gt;
      &lt;a href="#" data-file="data1"&gt;Load data 1&lt;/a&gt;
      &lt;a href="#" data-file="data2"&gt;Load data 2&lt;/a&gt;
      &lt;div id="dataContent"&gt;&lt;/div&gt;
  &lt;/section&gt;
  
  $(document).ready(function(){
      $('body').on('click','#section2 a',function(event){
          event.preventDefault();
          var datafile = $(this).data('file');
          var dataContent = $('#dataContent');
          // if there is content fade it out first
          if(dataContent.html().length){
              dataContent.addClass('opa fade');
              // check for completed transition
              dataContent.one('transitionend', function(){
                  dataContent.load(datafile + '.php', function(){
                      dataContent.removeClass('fade');
                  });
              }); 
          } else {
              // if there is no content just load and fade in
              dataContent.addClass('fade');
              dataContent.load(datafile + '.php', function(){
                  dataContent.removeClass('fade');
                  dataContent.addClass('opa');
              });
          }
      });
  });
  
  #dataContent.opa {
      opacity: 1;
      transition: opacity .700s; 
  }
  #dataContent.fade {
    opacity: 0;
  }
  </code></pre>
  
  <p>Still looking for a solution to this <strong>without jQuery</strong> using vanilla javaScript </p>
  
  <p><em>referencing these posts for help</em></p>
  
  <p><a href="https://blog.teamtreehouse.com/using-jquery-to-detect-when-css3-animations-and-transitions-end" rel="nofollow noreferrer">https://blog.teamtreehouse.com/using-jquery-to-detect-when-css3-animations-and-transitions-end</a></p>
  
  <p><a href="https://jonsuh.com/blog/detect-the-end-of-css-animations-and-transitions-with-javascript/" rel="nofollow noreferrer">https://jonsuh.com/blog/detect-the-end-of-css-animations-and-transitions-with-javascript/</a></p>
  
  <p>After spending all day thoughtfully researching this and pulling everything I could find from the web together I have a working solution. This is an example using <strong>plain vanilla JavaScript Ajax</strong> and <strong>CSS3 transitions</strong>. I have found this to be a popular trend in the last few years (2017-2019) as browsers have advanced an older browsers have fallen away. Also, with the dependency upon jQuery less and less it seems more people are looking for plain js versions and leveraging css3 transitions and animations. I believe this question and answer to be of more detail than the others linked here on stackoverflow and believe this example will be of use to many others.</p>
  
  <p>Here is the working solution</p>
  
  <pre><code>css
  #dataContent.opa {
      opacity: 1;
      transition: opacity .400s; 
  }
  #dataContent.fade {
      opacity: 0;
  }
  html
  &lt;section id="section"&gt;
      &lt;a href="#" class="clicker" data-file="data1"&gt;Load data 1&lt;/a&gt;
      &lt;a href="#" class="clicker" data-file="data2"&gt;Load data 2&lt;/a&gt;
      &lt;a href="#" class="clicker" data-file="data3"&gt;Load data 3&lt;/a&gt;
      &lt;div id="dataContent"&gt;&lt;/div&gt;
  &lt;/section&gt;
  var classname = document.getElementsByClassName('clicker');
  ajaxf = function(event){
      var xhttp = new XMLHttpRequest();
      event.preventDefault();
      var datafile = this.getAttribute('data-file');
      var dataContent = document.getElementById('dataContent');
      if(dataContent.innerHTML.length){
          dataContent.classList.add('opa','fade');
          dataContent.addEventListener('transitionend',handler);
          function handler(event) {
              event.target.removeEventListener(event.type,arguments.callee);
              xhttp.onreadystatechange = function(){
                  if(this.readyState == 4 &amp;&amp; this.status == 200){
                      dataContent.innerHTML = this.responseText;
                      dataContent.classList.remove('fade');
                  };
                  if(this.status == 404){
                      dataContent.classList.remove('fade');
                      dataContent.innerHTML = 'there was an error retrieving data';
                  }               
              };
              xhttp.open('GET',datafile + '.php',true);
              xhttp.send();
          }
      } else {
          dataContent.classList.add('fade');
          xhttp.onreadystatechange = function(){
              if(this.readyState == 4 &amp;&amp; this.status == 200){
                  dataContent.innerHTML = this.responseText;
                  dataContent.classList.remove('fade');
                  dataContent.classList.add('opa');
              };
              if(this.status == 404){
                  dataContent.innerHTML = 'there was an error retrieving data';
                  dataContent.classList.remove('fade');
                  dataContent.classList.add('opa');
              }
          };
          xhttp.open('GET',datafile + '.php',true);
          xhttp.send();
      }
  };
  for(var i = 0; i &lt; classname.length; i++){
      classname[i].addEventListener('click',ajaxf,false);
  };
  </code></pre>
  
  <p>One of the main keys in this process is creating an <strong>event listener</strong> for the <strong>transitionend</strong> and then removing the event listener (to repeat the function when the 2nd transition fires)</p>
  
  <p><a href="https://i.stack.imgur.com/QOORN.gif" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/QOORN.gif" alt="enter image description here"></a></p>