Drag and Drop table content with JavaScript

Content of HTML table cells can be dragged to another cell or another table. It isn’t difficult to define onMouseMove handler and change top / left element styles to move the object. In case with tables, you will have to determine somehow target cell. Attaching onMouseOver handler on TD elements will not work, because browser doesn’t fire events to the elements below the dragged object.

Anyway, after taking care of the current scroll position and calculating TD positions, REDIPS.drag should work in recent major browsers like Google Chrome, Firefox, Safari, Internet Explorer, Opera and mobile devices as well. Click on image below, will open live demo where you can drag green, blue or orange bordered DIV elements, change properties (radio button and check-boxes) and click on “Save” button.

Download latest version redips2.tar.gz

REDIPS.drag example01

In this example “Save” button will scan table content, create query string and send to PHP page. Demo shows how to collect content and accept parameters on the server side. More about accepting parameters you can read at Reading multiple parameters in PHP. “Clone” elements (orange in this demo) will be duplicated first because of “redips-clone” keyword contained in class name. If you drop object on cell named “Trash”, object will be deleted from the table (with or without confirmation). Library has built in autoscroll and option to forbid landing to non empty cells or cells named with class “redips-mark”. Table can contain rowspan / colspan TDs and different background color for every cell.

Here are minimal steps to enable content dragging in table:

  • put <script type=”text/javascript” src=”redips-drag-min.js”></script> to the head section
  • initialize REDIPS.drag library: <body onload=”REDIPS.drag.init()”>
  • place table(s) inside <div id=”redips-drag”> to enable content dragging
  • place <div class=”redips-drag”>Hello World</div> to the table cell

Other features of REDIPS.drag library:

  • methods and data structure are defined in namespace (easier integration with other JS frameworks)
  • all JavaScript code is checked with ESLint
  • REDIPS.drag documentation generated with JsDoc Toolkit
  • drag and drop table rows
  • movable DIV element can contain other HTML code (images, forms, tables …)
  • forbidding or allowing TDs marked with class name “redips-mark”
  • option to define exceptions and allow dropping certain DIV elements to the marked cell
  • option to define single content cell on the table declared with “multiple” drop option
  • cloning
    • for unlimited cloning add “redips-clone” class name to the DIV object
      <div class=”redips-drag redips-clone”>Hello World</div>
    • to limit cloning and transform last object to the ordinary movable object add ‘climit1_X’ class name
      <div class=”redips-drag redips-clone climit1_4″>Hello World</div>
    • to limit cloning and transform last object to immovable object add ‘climit2_X’ class name
      <div class=”redips-drag redips-clone climit2_4″>Hello World</div>
    • where X is integer and defines number of cloned elements (in previous examples, each climit will allow only 4 cloned elements)
  • unlimited nested tables support
  • dropping objects only to empty cells
  • switch cell content
  • switching cell content continuously
  • overwrite TD content with dropped element
  • shift table content
  • table cell with “redips-trash” class name becomes trashcan
  • enabled handlers to place custom code on events: changed, clicked, cloned, clonedDropped, clonedEnd1, clonedEnd2, dblClicked, deleted, dropped, droppedBefore, finish, moved, notCloned, notMoved, shiftOverflow, relocateBefore, relocateAfter, relocateEnd, rowChanged, rowClicked, rowCloned, rowDeleted, rowDropped, rowDroppedBefore, rowDroppedSource, rowMoved, rowNotCloned, rowNotMoved, rowUndeleted, switched and undeleted
  • deleting cloned DIV if the cloned DIV is dragged outside of any table
  • enabling / disabling dragging
  • animation (move element/row to the destination cell/row)
  • added support for touch devices (touchstart, touchmove, touchend)

How REDIPS.drag works?

Script will search for DIV elements (with class name “redips-drag”) inside tables closed in <div id=”redips-drag”> and attach onMouseDown event handler. When user clicks with left mouse button on DIV element, onMouseMove and onMouseUp handlers will be attached to the document level.

While dragging DIV element, script changes its “left” and “top” styles. This is function of the onMouseMove handler. When user releases left mouse button, onMouseUp event handler will unlink onMouseMove and onMouseUp event handlers. This way, browser will listen and process mousemove events only when DIV element is dragged.

As I mentioned, onMouseDown is defined on the elements you want to drag. Elements beneath the dragged object will not be able to catch onMouseOver event. Why? Because you are dragging object and that object only can catch the onMouseOver event.

So, to detect destination table cells, script calculates all cell coordinates (with scroll page offset) and store them to the array. Array is searched inside onMouseMove handler and after left mouse button is released, DIV will drop to the current (highlighted) table cell.

In redips2.tar.gz package you will find many examples including example of how to save/recall table using PHP and MySQL. Package also contains and redips-drag-min.js – a compressed version of REDIPS.drag library (compressed with Google Closure Compiler).

Happy dragging and dropping!

1,195 thoughts on “Drag and Drop table content with JavaScript”

  1. Hey, is posible to use your code to create a weekly schedule to drag and drop videos?

  2. Hi Darko. I’ve updated my test page to last release of your library. I want to use CSS3 flex functionality to sort divs inside cells so I’ve inserted a flex div inside every cell of the table. How can I drop objects inside cell’s flex div ?

  3. Hi Darko. Is there a away to set an order of DIVs dropped into a TD and recover it after reloading a page ?

    Thank you


  4. Amazing set of libraries.. Thanks for creating them and detailed blogs & APIs to go with them, you rock!!!

  5. Hi Darko,
    first of all, thanks for your great work. I’ve been experiencing a problem lately and I hope you might help: I’m using a element with id “redips-drag” as a container and I assigned it a fixed height via CSS with the overflow:auto option. When my table exceeds the fixed height of the container, the elements placed on the bottom of the table start acting funny: when I grab one of them, it shifts down towards the bottom of the page and it becomes very difficult to move it to another table cell. Do you have any suggestions?

  6. @Sue Maurizio – REDIPS container should nicely envelop tables with drag elements. The reason why is to minimise browsers workload. In your case maybe you shouldn’t fix containers height and let it to be dynamic. You can see in example16 where I had define only DIV width without specifying height. When you click on “table” button, height is changed but all tables are included inside drag container. Just set “border: 1px solid red” in DevTools to see how drag container is resizing dynamically.

  7. I’ve been looking for drag and drop for a while for a project on angular6.
    Great the code is working perfectly but won’t work until i reload the page
    I do receive the error ” Uncaught REDIPS.drag – Drag container is not set! “.
    I need a urgent reply please..

  8. Hi,
    the error is related to drag container. In the moment when library tries to set reference to the DIV element with id=”redips-drag”, this DIV element is not found. My suggest is to set REDIPS initialisation to the page “onload” event – after page is completely loaded and ready. Something like the following code:

    var redipsInit;
    // redips initialization
    redipsInit = function () {
    	// reference to the REDIPS.drag lib
    	var rd = REDIPS.drag;
    	// initialization
    // add onload event listener
    if (window.addEventListener) {
    	window.addEventListener('load', redipsInit, false);
    else if (window.attachEvent) {
    	window.attachEvent('onload', redipsInit);
  9. when I click the draggable item in the table; they rotate up-down->up
    How to make them do nothing when its just a click?

  10. Only clicking on DIV element (without moving) should not reoreder DIV elements in table cell. But click and little move (will highlight TD and) will be considered as dragging start – this will also remove element from flow. So when user releases mouse button and dragged DIV element is still on top of the same TD, DIV will be attached as a child to the TD at the bottom (if TD already contains more elements).

  11. Hello,
    Thanks for this library, it helped me on multiple projects. :) Though I’ve encountered one problem (probably browser related?).

    I got multiple cell coded like this:

    When I switch the divs with drag and drop, on most browsers it doesn’t click on the link and just switches the div, and only goes to the url when i click without moving (which is what I’m looking for). But not on mozilla firefox. Whether I only click on it or drag & drop it, it will go on the link. Any ideas on how to avoid that?
    Thanks and cheers. :)


  12. Hi Tatiana,
    as you said, this might be browser related issue. It will be of great help if you can set small show case on jsfiddle so I can see where is the problem and try to fix it. Here is link of REDIPS.drag examples on jsfiddle that can be used for new examples.


    I’m glad that my lib was useful and thanks for the feedback.

  13. Oh thanks that will make it much easier! Here it is:


    Like I said previously, no problem on most browers besides firefox. I can drag and drop without accessing the link, but on firefox as soon as you drop a div it goes on the link.

    Thanks for you help,


  14. Yes, FF somehow propagates click from the inner image to the parent link. Chrome works as expected. But with small trick, we can make wanted cross-browser behaviour (I hope). Please see forked jsfiddle example:


    Instead of wrapping image with <a href=”” … href location is written to the custom data attribute data-href. In case when user only clicks on DIV element (no dragging), notMoved() event handler will be invoked where is window.location.href set with value from data-href. Here is modified HTML:

    <div class="redips-drag" data-href="https://google.com/">
        <img src="http://www.dictionary.com/some.png" class="image">

    … and JavaScript:

    // in case when DIV element is not moved then do the magic
    // read custom data attribute (data-href) and point browser to the link
    rd.event.notMoved = function() {
        window.location.href = rd.obj.dataset.href;

    Hope this trick will help you with your app.

  15. It works wonders! Thank you very much for taking the time to help me :)

    Keep up the good work!

  16. Thank you for the great work!
    I’m at the moment working on a small project where I will use it.

    I will use it for a taskboard, like a kanban view. But I need to have some areas on the individual task that is not draggable, and some area there is draggable. Exampel: class: “card-img-top” could be used to drag the teask around and the rest of the task is not draggable.

    At the moment when i have class: “redips-drag” in the main div all inside is draggable.

    Maybe you have a good idea to solve that problem :)

    Improvements for TM mixers

    Extra long text..

    PR: 600932-02

  17. Love your work! I have one question though.
    I would like to split the div’s in two so I have a left and a right.
    I have done this and it works fine, but what I’m trying to achieve is if the left side is clicked for the move, run one code. If the right is selected run another.

    If I give the div’s an id, how can I reference that id?


  18. Inside every event handler reference to dragged DIV element is stored to REDIPS.drag.obj. If you need exactly id of dragged DIV element then it can be done this way:

    rd.event ...
        var id = rd.obj.id;

    Just search for “rd.obj” in examples to see how to use it.

Leave a Comment