JSFiddle - React, Tailwind, and code Playground

by Kerrick

HTML

<div id="canvas">
    <h1 class="draggable">Test</h1>
    <h2 class="draggable">Test 2</h2>
</div>

CSS

body {
    background: grey;
    margin: 0;
    padding: 0;
}

#canvas {
    background: white;
    width: 400px;
    height: 200px;
    margin: 0 auto;
    position: relative;
}

.draggable {
    -moz-user-select: none;
    -khtml-user-select: none;
    -webkit-user-select: none;
    user-select: none;
    cursor: move;
    background: #800;
    color: white;
    position: absolute;
    margin: 0;
    padding: 0;
}
[data-selected] {
    /*box-shadow: inset 0px 0px 10px white;*/
    outline: 3px solid #0C0;
}

JavaScript

$('#canvas')
    .click(function() {
        $(this).deselectAll();
    });
$('.draggable')
    .draggable({
        containment: '#canvas',
        delay: 200,
        grid: [1, 1],
        opacity: 0.8,
        snap: true,
        snapMode: 'both',
        snapTolerance: 4,
        start: function(event, ui) {
            $(this).select('data-selected', '#canvas');
        },
        stop: function(event, ui) {
        }
    })
    .resizable({
        autoHide: true,
        containment: '#canvas'
    })
    .dblclick(function(event) {
        event.stopPropagation();
        alert('editing');
    })
    .click(function(event) {
        event.stopPropagation();
        $(this).select();
    });

jQuery.prototype.extend({
    select: function(attribute, context) {
        context = context || '#canvas';
        attribute = attribute || 'data-selected';
        $(context).deselectAll(attribute);
        return this.each(function() {
            $(this).attr(attribute, '');
        });
    },
    deselect: function(attribute) {
        attribute = attribute || 'data-selected';
        return $(this).each(function() {
            $(this).removeAttr(attribute);
        });
    },
    deselectAll: function(attribute) {
        attribute = attribute || 'data-selected';
        return $(this).find('[' + attribute + ']').each(function() {
            $(this).deselect(attribute);
        });
    }
});