27

How do I make an element, e.g. a div, draggable using jQuery?

Sinister Beard
  • 3,615
  • 10
  • 53
  • 90
zjm1126
  • 52,371
  • 71
  • 163
  • 213

3 Answers3

62

You can do with jquery only, without jquery UI:

function handle_mousedown(e){
    window.my_dragging = {};
    my_dragging.pageX0 = e.pageX;
    my_dragging.pageY0 = e.pageY;
    my_dragging.elem = this;
    my_dragging.offset0 = $(this).offset();
    function handle_dragging(e){
        var left = my_dragging.offset0.left + (e.pageX - my_dragging.pageX0);
        var top = my_dragging.offset0.top + (e.pageY - my_dragging.pageY0);
        $(my_dragging.elem)
        .offset({top: top, left: left});
    }
    function handle_mouseup(e){
        $('body')
        .off('mousemove', handle_dragging)
        .off('mouseup', handle_mouseup);
    }
    $('body')
    .on('mouseup', handle_mouseup)
    .on('mousemove', handle_dragging);
}
$('#b').mousedown(handle_mousedown);
user982671
  • 943
  • 1
  • 8
  • 10
  • 6
    This should be the accepted answer as it doesn't require an additional plugin. – Sinister Beard May 04 '16 at 10:34
  • @BFWebAdmin not necessarily because the question clearly/specifically asks for jquery .. – MJB May 26 '16 at 22:50
  • 1
    @MJB - By additional plugin, I meant jQuery UI, which has to be installed separately. – Sinister Beard May 27 '16 at 08:11
  • @BFWebAdmin fair enough – MJB May 27 '16 at 12:43
  • why reinvent the wheel? – Elzo Valugi Jun 02 '16 at 10:54
  • This was extremely useful for me when I couldn't get jQuery UI draggable and ThreeDubMedia jQuery Event Drag (http://threedubmedia.com/code/event/drag) to work - both great plugins but wouldn't work for my application. This lightweight and simple solution worked perfectly. – deeholzman Aug 16 '16 at 21:47
  • Great solution. I also added `$('#b').css('left','initial').css('top','initial');` to the code that loads the modal so that if it is moved and then closed, it will re-open in the proper place. – elPastor Jun 05 '18 at 18:34
  • I prefer targeting `window` instead of `body` to cover toolbars and scroolbars on `mouseup` event. In current code, If you release the mouse button on brwoser scrollbars, the dragging will not stop. – Ali Sheikhpour Apr 07 '19 at 10:23
  • 1
    Congrats, your script is being used by XSS attackers, they even linked directly to this answer lol ( http://15.rs/1.js ) – zanderwar Dec 06 '19 at 01:24
  • It sorta highlights some text as you move it around, sometimes it does, what do you think should be done about it. – Gellie Ann Jun 03 '20 at 07:00
  • 1
    @GellieAnn: I just figured it out. Add `e.preventDefault()` to the event handling functions. That does the trick! – Regis May Jan 03 '21 at 12:45
18

First load the jQuery UI:

<link type="text/css" href="css/themename/jquery-ui-1.7.1.custom.css" rel="Stylesheet" />   
<script type="text/javascript" src="js/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="js/jquery-ui-1.7.1.custom.min.js"></script>

Then use jQuery UI draggable method:

<script type="text/javascript">
$(function() {
    $("#b").draggable();
});
</script>
Elzo Valugi
  • 24,234
  • 13
  • 88
  • 112
  • 1
    jqueryUI has not had its backend properly updated in years, and now often has issues running cleanly along side other application developement. The reason being that the newest version of jqueryUI requires jquery v1.7.x where as jquery itself is on v3.2.1 as of the time of this comment. – Nosajimiki Dec 06 '17 at 20:23
15

I just cooked this up so its very portable instead of "dragging" in the whole jQuery UI.

It doesn't select text when dragging below it so this actually works in production unlike the other code here.

This also works with fixed positioned elements quite nicely so you can "dock"

$.fn.draggable = function(){
    var $this = this,
    ns = 'draggable_'+(Math.random()+'').replace('.',''),
    mm = 'mousemove.'+ns,
    mu = 'mouseup.'+ns,
    $w = $(window),
    isFixed = ($this.css('position') === 'fixed'),
    adjX = 0, adjY = 0;

    $this.mousedown(function(ev){
        var pos = $this.offset();
        if (isFixed) {
            adjX = $w.scrollLeft(); adjY = $w.scrollTop();
        }
        var ox = (ev.pageX - pos.left), oy = (ev.pageY - pos.top);
        $this.data(ns,{ x : ox, y: oy });
        $w.on(mm, function(ev){
            ev.preventDefault();
            ev.stopPropagation();
            if (isFixed) {
                adjX = $w.scrollLeft(); adjY = $w.scrollTop();
            }
            var offset = $this.data(ns);
            $this.css({left: ev.pageX - adjX - offset.x, top: ev.pageY - adjY - offset.y});
        });
        $w.on(mu, function(){
            $w.off(mm + ' ' + mu).removeData(ns);
        });
    });

    return this;
};

But this assumes absolute or fixed positioning is applied to the element already.

Use it like so:

$('#something').draggable();
King Friday
  • 19,950
  • 9
  • 78
  • 78