JSFiddle - React, Tailwind, and code Playground

HTML

<script src="//canjs.com/release/2.0.3/can.jquery.js"></script>
<script src="https://rawgithub.com/ai/transition-events/master/lib/transition-events.js"></script>
<script type="text/mustache" id="something">
    <button name="add" can-click="addItem">Add</button>
    <hr/>
    {{#each items}}
        <div class="something {{animationState}}" data-token="{{token}}">
            <h1>{{title}}</h1>
            <button name="close" can-click="removeItem">Close</button>
        </div>
    {{/each}}
</script>

CSS

.something
{
    border-bottom: 1px solid silver;
    padding-bottom: 1em;
}

.something.removing
{
    opacity: 0;
    transition: 2s opacity;
    -moz-transition: 2s opacity;
    -webkit-transition: 2s opacity;
}

JavaScript

can.Component.extend(
{
    tag: "something",
    template: can.view("#something"),
    
    
    
    init: function(element, options)
    {
        this.scope.attr( "element", can.$(element) );
        
        can.batch.start();
        this.scope.addItem();
        this.scope.addItem();
        can.batch.stop();
    },
    
    
    
    scope:
    {
        count: 0,
        element: null,
		
		items: [],
        
        
        addItem: function()
		{
            this.items.push(
			{
                title: "Item " + (++this.count),
                
				token: (new Date().getTime() * Math.random()).toString().replace(".",""),
				animationState: ""
			});
		},
        
        
        getItemInfo: function(token)
		{
			var info = null;
			
			this.items.forEach( function(listElement, listIndex, list)
			{
				if (listElement.token === token)
				{
					info = {
						domElement:		this.element.find("[data-token="+token+"]"),
						listElement:	listElement,
						listIndex:		listIndex,
						list:			list
					};
					
					// Kill loop
					return false;
				}
			}, this);
			
			return info;
		},
        
        
        removeItem: function(token)
		{
            // If called with a declarative can-event
            if (typeof token !== "string")
            {
                token = token.attr("token");
            }
            
            var item = this.getItemInfo(token);
            var proxy = this;
			
			item.listElement.attr("animationState", "removing");
			
			item.domElement.afterTransition(function(event)
			{
				proxy.items.splice( proxy.getItemInfo(token).listIndex, 1 );
			});
		}
    },
    
    
    
    events:{}
});



$("body").append( can.view.mustache("<something/>") );