sergio

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

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

TwistingTwists

This blog uses sortableJS.
I haven’t used it personally, but if fly people are using it, makes me biased already.

slouchpie

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.

Where Next?

Popular in Discussions Top

Other popular topics Top

vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1144 53578 245
New
Nvim
Anybody knows a comprehensive comparison of Django and Phoenix, thanks for the help. Where are they similar? Where do they differ the m...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a &gt; b) do {:ok, "a"} end if (a &lt; b) do {:ok, b} end if (a == b) do {:ok, "eq...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

We're in Beta

About us Mission Statement