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 destination cell. Attaching onMouseOver handler on TD elements will not work, because browser doesn't fire events to the elements beneath the dragged object.

Anyway, after taking care of the current scroll position and calculating TD positions, here is example that should work in FF3+, IE8+, Google Chrome 10+, Safari 5+ and Opera 11+. Please try to drag green, blue or orange bordered DIV elements, change properties (radio button and check-boxes) and click on "Save" button.
Version 5.0.8
Download redips2.tar.gz
You can not drop here
(1) Clone
(2) Clone
Save content of the first table (plain query string)
Save content of the first table (JSON format)
Enable dropping to already taken table cells
Disable dropping to already taken table cells
Switch content
Switching content continuously
Overwrite content
Remove cloned element if dragged outside of any table
Confirm delete
Enable dragging

"Save" button will scan table content, create query string and send to the 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 "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). Script has built in autoscroll and option to forbid landing to the non empty cells or cells named with class "forbid". 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="drag"> to enable content dragging
  • place <div class="drag">Hello World</div> to the table cell

Other features of redips-drag.js:

  • functions and data structure are defined in namespace (easier integration with other JS frameworks)
  • JSLint: No problems found in redips-drag.js (tough one, huh)
  • REDIPS.drag documentation generated with JsDoc Toolkit
  • drag and drop table rows
  • movable div element can contain form elements, images and links
  • forbidding or allowing TDs marked with class name "mark" (depends on "marked_cell" parameter)
  • 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 "clone" class name to the DIV object
      <div class="drag clone">Hello World</div>
    • to limit cloning and transform last object to the ordinary movable object add 'climit1_X' class name
      <div class="drag clone climit1_4">Hello World</div>
    • to limit cloning and transform last object to immovable object add 'climit2_X' class name
      <div class="drag 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 "trash" class name becomes trashcan
  • enabled handlers to place custom code on events: clicked, moved, not moved, dropped, switched, changed, cloned, cloned end1, cloned end2, not cloned, deleted 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.js works?

Script will search for DIV elements (with class name "drag") inside tables closed in <div id="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 (159KB) package you will find 27 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.

Happy dragging and dropping!

This entry was posted on April 6, 2009 and is filed under Drag and Drop, JavaScript

Related posts

1,037 Responses to Drag and Drop table content with JavaScript

  1. Charan says:

    Is it possible to restrict the drag drop of a particular cell within the row it is part off??

  2. Jaison says:

    I need to drag and drop between columns only
    Can you help me??

  3. Kevin says:

    This is what I use to keep a DIV in its own table, you can use the additional data returned from getPosition() to limit to a row in the same table

    rd.event.droppedBefore = function () {
        // Get TO location
        var loc = rd.getPosition();
        // If this is not the same table the CELL came from cancel
        if (loc[0] != loc[3]) {
            return false;
  4. dbunic says:

    All dropping rules can be accomplished similar to the Kevin's simple example. You will only need to prepare some JS logic inside droppedBefore() event handler. getPosition() method returns array with target and source DIV position (please see documentation for more info).

    Kevin, thank you very much for helping.

  5. michael says:

    many thanks to the wonderful tools.
    but i encounter a problem that i'm making a single page app, and the drag table is generated, and when in other dropMode, it's ok. but when set to 'shift', i got an err "Uncaught TypeError: Cannot read property 'cells' of undefined" in line 3763. one more thing, when i tryed save the page, and visit from local, everything is fine.

    I do run the init() method after generated all elements.

    so, any tips to help me get through the problem? many thanks!

  6. fred says:

    I tried to put this ajax trigger:

        type: 'POST',
        url: 'set_order.php',
        data: 'positions=' + source.rowIndex + ';' + pos[1],
        success: function (data) {

    in the rd.event.rowDropped event but the ajax is not triggered... any clue to help ?

  7. dbunic says:

    @michael - I'll not exclude a possible bug and this problem might be related to missing TD properties needed for REDIPS.drag library. For some deeper inspecting I'll need a prepared example - like link to your page or JSFiddle. Here is link to existing REDIPS.drag example that can be reused for your demo:


    @fred - First you have to confirm that event is triggered at all. Place the following JS code to the event handler:

    var el = document.getElementById('myMessage');
    el.innerHTML = 'Event triggered';

    ... and you'll need to place "span" HTML tag the page:

    <span id="myMessage">Test</span>

    If "span" message is changed then event is invoked and the problem is somewhere else.

  8. shao says:

    Is it possible to prevent any changes to the div positions if the user drags it to somewhere that is not a table cell? It would be useful if a user, upon finding out that he/she doesn't want to move the div and has forgotten where it was originally, wanted to put it back.

  9. John says:

    I am sorry but I don't get how to keep a cell in its own table. How should I use Kevin's script? Thank you in advance. Great Documentation I hope to be able to learn more.

  10. dbunic says:

    @shao - Dragged DIV can be placed only to TABLES (table cells) that are inside "drag" containers. Anyway, if needed, it's possible to mark source cell (set another color) and set it back after DIV element is dropped. Please take a look to the event.moved() and event.dropped() documentation. In both events you have reference to the source cell (rd.source) and you only need to set background color ...

    @John - Actually it's not "cell" staying inside table but it is DIV element. So, when user drags around DIV element and in a moment when DIV element is dropped to the table, event.droppedBefore() will be triggered. If "false" is returned from event handler, DIV element will be placed to the source cell.

  11. RomanK says:

    Great tool!! I just have discovered it this morning... and already up and running for my project! Simply awesome!

  12. Pat Harding says:

    Hi dbunic,

    I'm building a prototype study plan and wanted to reduce the use of tables, I have limited the tables to the drag areas but noticed the div id=drag is interrupted by other div elements (with an id) outside of tables.

    Is it possible to ignore these id's? I am using them for js but I want the tables as one container.


  13. dbunic says:

    @RomanK - I'm glad you found REDIPS.drag useful for your project. Cheers!

    @Pat Harding - REDIPS.drag library needs to have defined drag container (DIV element with id="drag"). This is important because only this region will be scanned (instead of whole page) for TABLE/TD and changes that might happen. Element id on page should be unique (as its name suggests -> id - identifier), but browser will not complain if page contains several elements with the same id (to be honest, more elements with the same id is not by the DOM specification).

    In short, DIV id="drag" defines drag container and it's needed for REDIPS.drag library.

  14. Surya says:

    Hi dbunic,

    Its been a while working on with the drag and drop feature. I have a question for you. User specifies the starting and ending position in the table, all the td contents have to move in between those specifications. Is there any i could solve this problem.

    Earlier i worked with the moveObject() function and move all the stuff on the client side but right now i would take the request from the user and need to move these data.

    Once again thanks for your time and help.

  15. Phil says:

    I would like to clone fields cover one table field, fields covering two fields.
    How would you do this in a the most simple way?


  16. Paolo says:

    Hi dbunic.
    First of all I want to say "thank you" for your library. It is very useful!
    I have a question that is difficult to explain with my poor english.
    I have two tables, one hovers the other. The biggest one is greater than the viewport (and I have to scroll it to see certain cells). When the viewport is NOT positioned at the left-top of it and I want to drag a DIV from the small table (that hovers the big one with CSS = position:absolute) to the big one, the big one starts to scroll automatically. This is a problem for me.
    It doesn't happen when then viewport is located at the left-top of the big table.

    Thank you in advance.


  17. Victor says:

    Hi everyone!

    Is there any way I can adapt this drag and drop to work on lists instead of tables?


Leave a Reply

Your email address will not be published. Required fields are marked *


In case of posting HTML tags or JavaScript code please convert special characters to HTML entities.
Especially pay attention to convert "<" character to "&lt;" entity!