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!
Great piece of code!!!
When cloning an element, I have noticed that the cloned element is the one that stays in the source cell while the original is moved to the target cell. I need just the opposite, is there a way to accomplish that?
Thanks!
@Alex – Cloned element should be the one that is moving while original stays in source_cell. After cloning and dropping element to the target_cell, open DOM inspector and click on both elements. Original elements should have unchanged ID while cloned element will have ‘c0’ appended to the ID. Inside myhandler_dropped() you can reference obj (cloned element) and obj_old (original element) …
Hi Darko
I am currently using you drag and drop code for a school project. Works great, except now I am adding a JavaScript Calendar inside the DIV’s. This messes up the limitiations I have used with mark and only – I can now move DIV’s where I shouldn’t be allowed to …
How do I impose restrictions on these new DIV’s that are on my page?
/Andreas
Hi Darko,
This excellent piece of code.
I did a code review and the code is clean and well readable, so I can easily adapt it to my needs. Great job.
I’m thinking about extending the drag object with a resize function.
What would be the best approach to do:
make colspans or play around with the div ‘position’ static but this might impact the whole code?
Is the code foreseen for this kind of extension and what might be the biggest risks I migth run into?
@Andreas – In case where dropping rules exists, you should manually add rules for every newly created element. This rules can be added inside event handlers. Please see example07 where rules are added for cloned elements. Here is part of JavaScript code from example07:
@Thim – REDIPS.drag is verified with JSLint so it has to be nicely indented and I’m trying to comment the code to be understandable – thanks.
DIV object can be resizied with changing styles ‘width’ and ‘height’. Of course, after applying new ‘width’ or ‘height’ to the DIV element, table cell and table column will be resized as well. So you want to merge two table cells instead of allow automatic column expanding. This approach is possible, and should not be a problem with REDIPS.drag – just call REDIPS.drag.init() method after merging table cells.
Don’t know what you mean about “div position static” … position: static is a default element position and in a moment when DIV is moved, REDIPS.drag changes position style to “fixed”. After element is dropped to the table cell, position is returned to “static”.
Anyway, any code modification / improvement is more then welcome (whole package is also pushed to the GIT).
Cheers!
great code,
i have a problem that I need unlimit nest table support for dragging,but the example seems support 2 nest tables..
how can i solve that?
Hi Darko,
I have 2 tables, one which is 1 x 3 (row x col) holds only pictures of relatively big size (say 300px by 200px), the other table which is 4 x 5 holds only names (of the pictures). Some other program loads the pictures on the “picture” table and then you can drag them, as many times as you like, to any cell on the “name” table but instead of the picture, its name is placed on the cell. I changed from image to text in myhandler_clonned(), but while dragging around the screen, the name is so far away from the cursor that it is annoying because the offset is calculated based on the picture size, not the name. Is there a way to accomplish this?
Again your code is great and your comments help a lot in understanding it
Congrats!!!
I think your library is very useful, and its really easy to use, i had a problem implementing it
i saw you write you use a scroll offset position, this is done so a div can be draggable even if you scroll what?, a div?, because i have a very large table both in width and height, i have scroll bars on the web page on the bottom and on the right, but i cant drop elements on the cells left outside the screen by the right, i can move divs up and down in whatever direction but the cells on the right cant receive a dragged div,
what can i do about this?
Thanks a lot!
@pin – REDIPS.drag is fixed and new release 4.1.0 has unlimited support for nested tables. Download latest redip2.tar.gz and try example13 – Nested tables.
@Alex – Images should be inside <div class=”drag”></div> like any other content – for example form elements or smile image in this demo. If you unpack redips2.tar.gz to the document root of your PC, please try example16. This example is a little bit complicated, but is good enough to show complex content in DIV elements and how to clone elements in the right tables (with shift key). If you have any other questions don’t hesitate to ask.
@Miguel Durazo – I suppose that main drag container is smaller then tables you have. First please try to make <div id=”drag”></div> visible with the following CSS:
and then expand DIV width if needed or simply add display: table property to wrap whole content:
Failed in cloning when moving div.
Could you guess what’s wrong?
…
I found my code works with Chrome but not with IE8.
@Shawn Lee – Do you have some example to show me where is the problem so I can locate and fix the BUG (if BUG exists)?
Thank you
Would it be possible to implement this library so that content could be dragged to table cells and then stored as the value element when writing to a flatfile database?
Thanks
Andrew Harris
Hi Darko,
Thank you for your reply.
Please go to the above url and you can see the situation under which two web browsers (IE8 and Chrome) react different.
You may not see source code because an ASP populates innerHTML of a “div”.
Another issue with even Chrome is that cloned object is not wrapped (becoming a longer rectangle) when the original is word-wrapped.
@andrew harris – Content of the HTML table could be processed on any way. REDIPS.drag library adds drag and drop functionality so DIV content in table can be arranged and after that saved. Public method REDIPS.drag.save_content() will scan table content, prepare position, element Id and return query string ready for sending to the server. You can make modification or create your own save function based on this method (customized for your needs).
@Shawn Lee – I visited example and only Chrome managed to open the page. IE8, Opera11 and FF3.6 displayed the following error:
Anyway, I saw that DIV elements don’t have defined width. It’s understandable that elements in your example could not have the same width, but if you can calculate width for each element and assign it – that will be fine. Otherwise, in a moment of dragging, offset will occure. Maybe the undefined DIV width causes problems …
I’ve tried out with div having width in % but the result was same.
It works with Chrome but not with IE8.
I think I have to use your library without moving clone since dropping works perfect.
Thank you for your time.
I appreciate your program of Drag and Drop Table Contents.
@Shawn Lee – Which element on your demo is clone type? I tried to move every element with Chrome and none of them has clone option. Clone elements should have defined clone class. For example:
And you can define different color for clone class so this type of elements will be easy to distinguish. Or you can generally define that every element could be cloned with SHIFT key. After initialization set clone_shiftKey property to true:
If you have more time and will, you can prepare working offline demo and send me. I will try to analyze where is the problem. Thank you!
This is a fantastic piece of drag-n-drop code and exactly what I needed for my project! Thank you! I also appreciate your desire to explain the inner workings of the script in a thoughtful and understanding way, and to include multiple examples in the package. Fantastic work! :-) I’m assuming it’s possible to mark a table cell so that one cannot drag a second element into it? Thank you again!
Ah… I figured out my last request! I needed to change the ‘drop_option’ variable to ‘switch’ in in the script.js include page (I had only changed it in redips-drag.js), and now I’m a happy Padre! Here is a peek at my pending implementation of your drag-n-drop code using images! :-)
http://deadmans.geocaches.org/order_of_the_franciscans.html
Thanks again!! :-)
@Jim Epler – I must admit that your application looks very cool. Excellent example of using images and REDIPS.drag library. And I’m glad you solved the problem – super!
Cheers