JSFiddle - React, Tailwind, and code Playground

by Optimix

HTML

<div class="demo-wrapper">
    <div class="image-wrapper image-wrapper--loading">
        <img class="image" src="" />
    </div>
</div>
<p>Hit the button!</p>
<button class="load-image">Load Image</button>

CSS

.demo-wrapper {
   max-width: 320px; 
}
.image-wrapper {
    width: 100%;
    padding-bottom: 66.67%;
	border: 2px solid black;
    position: relative;
	background: white;
}
.image-wrapper img {
    position: absolute;
    width: 100%;
    -webkit-transition: opacity 1s;
     -moz-transition: opacity 1s;
       -o-transition: opacity 1s;
          transition: opacity 1s;
    opacity: 1;
}
.image-wrapper--loading {
    background: white url(data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH+GkNyZWF0ZWQgd2l0aCBhamF4bG9hZC5pbmZvACH5BAAKAAAAIf8LTkVUU0NBUEUyLjADAQAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQACgABACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkEAAoAAgAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkEAAoAAwAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkEAAoABAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQACgAFACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQACgAGACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAAKAAcALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA==) center center no-repeat;
}
.image-wrapper--loading img {
     opacity: 0;
}

JavaScript

$(document).ready(function() {
    // when the image has loaded
    $('.image').load(function() {
        // remove loading class from the wrapper
         $(this).parent('.image-wrapper--loading').removeClass('image-wrapper--loading');
    });
    
    var imagePath = 'http://andyshora.com/assets/img/pages/grumpy-cat.jpg';
    
    // delaying the loading of the image so you can see the loading state
    $('.load-image').click(function() {
     $('.image').attr('src', imagePath + '?' + Math.random());
    });
    
});