sergio
What's a great modern drag and drop javascript library you recommend?
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browsers. Modern browsers may have shiny new API’s that are not being leveraged by older plugins.
What’s a great, modern drag and drop plugin you would recommend?
One feature I’m trying to build: I’m trying to replicate the Trello list drag and drop feature where you can drag cards between lists, and drag the lists around as well.
One plugin I found is draggable by Shopify: Draggable JS – JavaScript drag and drop library But it’s not maintained anymore, and has a ton of open PRs.
Another plugin is Sortable: GitHub - SortableJS/Sortable: Reorderable drag-and-drop lists for modern browsers and touch devices. No jQuery or framework required.
Thanks!
Most Liked
tlietz
After many hours of research, I have finally found a dnd library that is built for vanillajs first, is actually performant (uses webworkers), has a good auto scroll out of the box, and is used in production applications:
Additionally, it doesn’t use the native drag and drop web api, which means that it doesn’t over-scroll in a glitchy way on mobile, and the dragged element can be constrained to a certain axis since it doesn’t need to follow the cursor.
It’s more of a layout engine, but there are Kanban examples that can easily be pared down to do what scrollablejs does.
TwistingTwists
This blog uses sortableJS.
I haven’t used it personally, but if fly people are using it, makes me biased already.
slouchpie
I was looking at Muuri today and trying to get the Kanban example working. Examples | Muuri Docs It took me some time to turn the CSS into tailwind and break the HTML into small functions so I am pasting what I did here. Hopefully it helps somebody else get started with Muuri + Phoenix.
defmodule MyAppWeb.MuuriLive.Kanban do
@moduledoc false
use MyAppWeb, :html
def kanban(assigns) do
~H"""
<div id="muuri-kanban-demo" phx-hook="KanbanHook">
<div class={["drag-container", "fixed top-0 left-0", "z-[1000]"]}></div>
<div class={["board", "relative"]}>
<.board_column header="Todo" indexes={1..5} />
<.board_column header="Working" indexes={6..10} />
<.board_column header="Done" indexes={11..15} />
</div>
</div>
"""
end
attr :header, :string
attr :indexes, :integer
defp board_column(assigns) do
~H"""
<div class={[
"board-column done",
"absolute top-0 left-0",
"py-0 px-[10px]",
"w-1/3",
"z-[1] muuri-item-releasing:z-[2] muuri-item-dragging:z-[3] muuri-item-dragging:cursor-move"
]}>
<div class={[
"board-column-container",
"w-full h-full"
]}>
<div class={[
"board-column-header",
"relative",
"h-[50px] leading-[50px]",
"overflow-hidden",
"py-0 px-[20px]",
"text-center",
"bg-green-500",
"text-white",
"rounded-sm",
"font-bold",
"tracking-[0.5px]",
"uppercase"
]}>
<%= @header %>
</div>
<div class={[
"board-column-content-wrapper",
"relative",
"p-[8px]",
"bg-blue-700",
"h-screen",
"overflow-y-auto",
"rounded-sm"
]}>
<div class={["board-column-content", "relative min-h-full"]}>
<.board_item :for={index <- @indexes} index={index} />
</div>
</div>
</div>
</div>
"""
end
attr :index, :integer
defp board_item(assigns) do
~H"""
<div class={[
"board-item",
"absolute w-full m-[8px]",
"muuri-item-releasing:z-[9998] muuri-item-dragging:z-[9999]",
"muuri-item-dragging:cursor-move",
"muuri-item-hidden:z-[0]"
]}>
<div class={[
"board-item-content",
"relative p-[20px]",
"bg-white",
"rounded-[4px]",
"text-[17px]",
"cursor-pointer"
]}>
<span>Item #</span><%= @index %>
</div>
</div>
"""
end
end
and the hook
import Muuri from "../../vendor/muuri";
const KanbanHook = {
mounted() {
var dragContainer = document.querySelector(".drag-container");
var itemContainers = [].slice.call(
document.querySelectorAll(".board-column-content"),
);
var columnGrids = [];
var boardGrid;
// Init the column grids so we can drag those items around.
itemContainers.forEach(function (container) {
var grid = new Muuri(container, {
items: ".board-item",
dragEnabled: true,
dragSort: function () {
return columnGrids;
},
dragContainer: dragContainer,
dragAutoScroll: {
targets: (item) => {
return [
{ element: window, priority: 0 },
{ element: item.getGrid().getElement().parentNode, priority: 1 },
];
},
},
})
.on("dragInit", function (item) {
item.getElement().style.width = item.getWidth() + "px";
item.getElement().style.height = item.getHeight() + "px";
})
.on("dragReleaseEnd", function (item) {
item.getElement().style.width = "";
item.getElement().style.height = "";
item.getGrid().refreshItems([item]);
})
.on("layoutStart", function () {
boardGrid.refreshItems().layout();
});
columnGrids.push(grid);
});
// Init board grid so we can drag those columns around.
boardGrid = new Muuri(".board", {
dragEnabled: true,
dragHandle: ".board-column-header",
});
},
};
export { KanbanHook };
I will be changing the JS to use this.el. For now, it is identical to the JS given in their example.
It works nice. It “feels” better than sortable, which was my go-to for drag-n-drop
The tailwind modifiers I added like this:
plugin(({ addVariant }) => addVariant("muuri", [".muuri&", ".muuri &"])),
plugin(({ addVariant }) => addVariant("muuri", [".muuri&", ".muuri &"])),
plugin(({ addVariant }) =>
addVariant("muuri-item", [".muuri-item&", ".muuri-item &"]),
),
plugin(({ addVariant }) =>
addVariant("muuri-item-shown", [
".muuri-item-shown&",
".muuri-item-shown &",
]),
),
plugin(({ addVariant }) =>
addVariant("muuri-item-hidden", [
".muuri-item-hidden&",
".muuri-item-hidden &",
]),
),
plugin(({ addVariant }) =>
addVariant("muuri-item-positioning", [
".muuri-item-positioning&",
".muuri-item-positioning &",
]),
),
plugin(({ addVariant }) =>
addVariant("muuri-item-dragging", [
".muuri-item-dragging&",
".muuri-item-dragging &",
]),
),
plugin(({ addVariant }) =>
addVariant("muuri-item-releasing", [
".muuri-item-releasing&",
".muuri-item-releasing &",
]),
),
plugin(({ addVariant }) =>
addVariant("muuri-item-placeholder", [
".muuri-item-placeholder&",
".muuri-item-placeholder &",
]),
),
in tailwind config js.







