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)
- for unlimited cloning add “redips-clone” class name to the DIV object
- 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!
I am not sure whats wrong, but this still doesnt work. However this is what i was able to figure it out. When you call myhandler_dropped call looks like target cell looses its DIV tag as a result doesnt get picked up by save_content() as result i never see last drop cell’s DIV tag when i alert query variable in save_content function.
hi, i used this drag and drop clone concept, it works fine in all browsers except opera browser… is there any hacking code for opera browser or want to specify any width for the dragging div..? in opera browser even dragging the div also not acceptable…? give me some solutions to drag the div in opera browser to solve the problem…
Great stuff.
I was looking for all the other draggables/droppables implementations with jQuery and the other frameworks, and all look too complex for my taste.
This looks great.
One suggestion, although my guess is that it may not be that easy to implement, would be to allow a sortable style behavior. Right now if I have a one column table, with say, 20 objects and I want to move the last one to be in the second place, while pushing all of the other down, I cannot do it (as far as I could tell).
Anyways, thanks a lot for sharing this.
thank you very much
truly i didn’t try it but really thanks
Mr dbunic,
I’ve been using your wonderfull script, but I want to upgrade it with radio buttons. This comes with some difficulties I cannot overcome.
1. When dragged, the selected radio button is reset. Is there a way to keep the radio button checked while dragging and dropping?
2. I read your post about checking which checkboxes are ticked. Can this be implemented in the resulting query string as well? I’m saving the positions, but I’d like to save which radio button is checked as well.
Thanks for looking into this!
Absolutely amazing code. Exactly that I need. Thank you.
I want to have a table cell that, when clone is dragged onto it, the cloned element gets added to all the cells in that row. Can someone point me in the right direction? Thanks!
hey, cool script
i have discoverd the script for two days but i have a problem with reordering. i didn’t find correct way to reorder when single-cell drag-dropping. Dragged divs is always pushed last position in td.(always appen last did not insert) is anyone know the way to solve this problem? Thanks
How can I click on a button and reset one of the div’s to go back to default position that it started from?
Excellent code, does almost everything I need it to!
However I’m having an issue with the scrolling when inside a container. Am I doing something wrong or is it not possible to scroll according to it’s parent container?
e.g. I have my “drag” div inside an asp.net panel control and at present the panel is not scrollable when dragging near it’s boundaries.
Any help would be greatly appreciated.
Thanks.
First my apologies for a delay … I was busy for the last few weeks.
@HKad – I sent prepared example to you with 2×2 table so I assume that problem is solved.
@senthil – Drag and drop works in Opera 10.50 version. I made tests on following examples:
Drag and drop table content with JavaScript
JavaScript Drag and Drop example 2
JavaScript Drag and Drop example 3
… and everything works just fine. I would be grateful if you can make a little more detailed description of the problem – thanks.
@Danny – This JavaScript framework still doesn’t have option to move other objects from dropped position. Your suggestion seems OK and I will consider it in future development. Thank you!
@Garwain – I noticed form element reseting in IE6 browser. IE8, FF3, Google Chrome and Opera 10 doesn’t have this problem. Maybe there can be workaround to remember form element settings before dragging and to set values after element is dropped. This is just a hint to fix drag-n-drop form elements for messy IE6 but I would rather make browser upgrade ;)
http://www.ie6nomore.com
And yes, you can modify save_content() function to send radio buttons values. After function scans desired table, you can make form elements loop and append values to the URL. On the server side, script should differ DIV positions and form element values.
@Andy – JavaScript Drag and Drop example 3 is modified. If checkbox in upper left corner of main table is checked then school subject will be placed across table row. Hope this code in myhandler_dropped() will help you.
@Fatih – After mouse button is released, dragged DIV is moved from his parent node to the selected table cell. Actually, DIV is appended to the end of the list of children of a specified table cell. Maybe it could be possible to reorder elements in the same table cell and I will consider your sugestion in future releases. Thank you.
@Rocky – To return dropped DIV element to the previous location, place this line in button onclick event:
REDIPS.drag.source_cell.appendChild(REDIPS.drag.obj);
@Poz – Unfortunately scrolling works only on browser window. So, if table is bigger then browser window and element is dragging near to window edge, main window will start to scroll.
Thanks for the code, it was something that gave me a quick start to a completely expanded process for this application using multiple div’s and variable input drawn from a database, using also the mark parameter to limit where users could drag the db info since used for a schedule system, and the info can’t be dragged into wrong sections, that I used NAME=’$var’ in the div as well to pass the variable div names back with section1-1 – 50 , allowing me to save the results back to the db to the correct corresponding fields. The only thing I found to be an issue was I like to use an _ to delineate multiple layers of variables, but found this couldn’t be used, but that is a minor fix.
Hi,thanks so much for the code. Would you mind sending me the 2×2 table that you mentioned you prepared? Thanks again.
Hello dbunic,
i searched for log time to find a code thats beautiful like yours! Fantastic. But more fantastic is your support here in the comments!
Do you think, it is possible to change the “Example 3: School timetable” in that way, that dragged cells from the left table1 are away after dragging in that table1 and the cell could be cloned in timetable by dragging it under pushing (holding) ctrl/Strg key? Or something like that idea?
Anyway, great work!
Hi dbunic,
I have implemented a dynamic generation of this table based on an input text. The table is generated in the same page as the input field through XMLHttpRequest. I also pass the include to drag.js. However, the table is rendered ok but the cells are not draggable ! Is there a way to fix this ? Thanks for helping !
Hi dbunic
Was wondering if there was a way to forbid one type of cell being dragged to, lets say, a column or table.
For instance, in example 2, is there a way to forbid orance cells being dropped on the green squares. Currently, you can drop them even though they were not intended to be there. Forbid by color, or some other marker?
Thanks
@Richard Guyon – Yes, ‘_’ is used in save_content() to disjoin DIV id and table position (row and column). You can modify save_content() and replace ‘_’ with other separator, but don’t forget to apply modification on server side where parameters will be accepted.
@Ceola – Hope you receive my e-mail …
@Newhere – Yes it could be possible. First DIV elements in table1 (left table) declare as “normal” elements (cut out “clone” from class name) and in line 385 instead of:
if (moved_flag === 0 && obj.className.indexOf(‘clone’) > -1) {
add evt.ctrlKey
if (moved_flag === 0 && (obj.className.indexOf(‘clone’) > -1 || evt.ctrlKey)) {
That means, in moment when DIV element is moved for the first time and if it has “clone” in class name or ctrl key is pressed, element will be cloned. It’s a nice feature and I will upgrade drag.js to allow cloning if ctrl key is pressed. Thank you!
@mduran – During the past few months, drag.js was changed and automatic initialization is no longer part of the main code. So, to enable content dragging, you have to include drag.js and after page is loaded call REDIPS.drag.init() …:
in head section:
<script type=”text/javascript”>
window.onload = function () {REDIPS.drag.init();}
</script>
or in body tag:
<body onload=”REDIPS.drag.init()”>
@CaptainPlum – Hmm, in example 2 only green DIV elements can be dropped to the green cells. By default, marked table cells are forbidden for landing but you can make exception. Please see in example 2 how to make exception with the following code:
REDIPS.drag.marked_exception.green = ‘green_cell’;
REDIPS.drag.marked_exception.greenc0 = ‘green_cell’;
REDIPS.drag.marked_exception.greenc1 = ‘green_cell’;
Example 2 was tested with IE8, FF3 and Google Chrome and orange DIV element can’t be dropped to the green cell.
Hello dbunic,
I am the one, who has to Thank You! :-)
And your “ctrl-hack” works like a charm! So, Thanks again to you.
I am sure, I will have another 2 or 3 questions to you by working with your code in the next days.
So I will post it here and hope, you support it as fantastik as in the past.
BTW, you documented (I mean your coments in script-code) your code very good!
Thanks dbunic … I see it works on example two, I must have not updated something … :) Appreciate it.
Hi dbunic,
what do I have to do for changing your example3 in splitting table2 (Mo, Tue, Wed) into table2 (at the top of the right DIV) and into table3 (Thu, Fri, Sat) (at the bottom of the right DIV).
I tried it by copying the div#drag #table2-part in another div#drag #table3-part. And I added a table id=3 below table id=2 in the right DIV with same code as table id=2.
Result is, that the DIVs which I was dragging, has highlightend the wrong cells an also went into that wrong fields, except if I dragged the DIV first over row 1 of table id=2. Than every thing worked fine for that single dragging-process.
In every cases the saving-result was wrong by having only the table id=2- results in itself.
Can you please help me with this problem? I hope, my school-english is good enough for explaining my problem.