I have no idea how DFlex works under the hood (nor any other modern drag & drop library), but I'll share something clever I came up with. I'm sure others arrived at a similar solution.
I had to build something for my employer's website maybe 12-15 years ago. jQuery was the hot, new thing at the time. So was customizing UI. All available solutions used a combination of absolute positioning & coordinates to determine the interactivity of the elements. As you can imagine, it was a finicky, buggy mess.
I found myself wishing I could just use the DOM's own mouseover event -- but that didn't work, because the cursor was only over the element being dragged. My epiphany was this: When an element was picked up (drag start), I could duplicate every element in the set and set their opacities to zero (I called them "ghosts"). If I gave them a higher z-index than the element being dragged, mouseover events would be triggered on the ghost elements and I wouldn't have to do anything with coordinates, ever. It was also, by far, the most efficient solution at a time when browsers kinda sucked.
(I finally had a reason to share this anecdote.)
Anyway, thanks for this library, I'll be taking a look!
Cloning elements and duplicating containers are what DFlex tries to avoid. Because the usual implementation is to clone the element (ghost it) and then append a new one with a fixed position. The result is to reconstruct the DOM tree directly with every user interaction which leads to poor user experience and not a very practical transformation. That's why the default thing to do with DFlex is not to clone or change the element position unless there's a need to do so, for example: transforming from a container with a scroll.
To be clear, though: In my old example, there would only be DOM manipulation on drag start and drag end. All interactions between are handled with JS and CSS.
Hi HN, DFlex author here. I built DFlex because I couldn't find a comprehensive solution for interactive apps. All existing solutions depend heavily on HTML5 drag and drop to achieve interactivity despite the fact that the standard implementation is not designed to turn the apps into an interactive ones. So I started from scratch, built the transformation mechanism, and implement a custom reconciler built specifically to deal with DOM transformation. It also has a concurrent registration to prevent any blocking event and reduce initial loading. I also tried to take care of browser painting and scripting time. It's still in development mode but I'm glad it's shared here. Happy to take any questions you have and I'd love to get your feedback.
A request: could you please remove "case" from the font-feature-settings on the root element of https://www.dflex.dev/. It’s wrong (its purpose is to tweak vertical positioning of punctuation to align with all-caps text, which is not the case here), and some fonts (including a couple of the largest font foundries) also have "case" effectively imply `text-transform: uppercase`, and I’m using such a font, so the entire site is inappropriately uppercase for me.
(The rest of the font-feature-settings declaration also doesn’t make much sense: "case" 1, "rlig" 1,"calt" 0: rlig is for other scripts, and calt is a weird thing to turn off. I’d remove the entire declaration.)
The live demo[1] is completely unusable for people relying on assistive technology like screen readers and speech recognition, plus anyone using alternative input modalities like the keyboard. Do you have accessibility on your roadmap, to ensure that you're not encouraging users of your library to exclude a large percentage of the world's population?
Thanks for pointing out the accessibility issue. DFlex stands for a better user experience that includes of course adding accessibility to the main mechanism. At least the essential one. But at this moment, the project is still in development mode and many things need to improve including accessibility.
I spent a long time a few weeks ago looking for a replacement for jQueryUI's sortable(), but none of the DnD libraries supported both sortable and the grid option out of the box. Would yours work for that?
Here's where we want to use it:
https://pamelafox.github.io/faded-parsons-static/problem.htm...
Good question. Internally every registered element has a grid position inside its own container [1]. And it's not CSS grid styling, it actually calculates the geometry in each element and positioned them relative to their parent container. This is the implementation behind the enhanced transformation. Based on the grid position, DFlex can call the right method responsible for transformation instead of checking siblings linearly. For example, if you transform an element in the middle of the container it only invokes the switching position method instead of iteration in the entire tree. Still, grid implementation is not fully implemented and supported yet. But it's something that can be done in the next releases. However, the link you shared has an interesting case because you are resizing the element when appending it to the new container. I'd like to see a repo if it's possible but it's a very interesting case I'd love to look into it.
I was wondering if DFlex supports nesting containers inside items in infinite depth.
I saw you had nested example but I couldn't drag on item on the other container.
None the less promising, you say it's still in development, is there some aspects you are more specifically working on?
It's designed to handle nesting, so each register element can have depth starting from zero. But it's not finished yet. There are so many aspects to cover but nesting is not fully implemented. My priority right now is to enhance scrolling and migrate between scroll containers.
Edit: I'd like also to hear back from the community, I welcome any suggestions about the roadmap and what's necessary to be shipped soon.
In the nutshell, it's designed to drag an element into a droppable area. So let's say you are dragging a file to be uploaded, in this case, it makes perfect sense to use HTML API. Otherwise, you need a framework that can orchestrate the transformation. It's like using React. In theory, you can manipulate DOM directly in the browser but instead, you use a framework to build your app.
Having done something similar before, 2 things really hard to get right:
- animate position shift when the list is reordered. you can't rely on natural dom ordering to properly animate all items
- anything that has to do a tree structure
DFlex doesn't reorder the elements. 1- It transforms elements by calculating the new position so it can avoid any layout shift this is something essential in the transformation mechanism. 2- It reconciles the transformed element when needed. So instead of replacing the entire children, it replaces only the transformed ones.
dnd-kit is maintained by someone who works at Shopify, but I'm not sure if it's a direct successor or just similar project: https://github.com/clauderic/dnd-kit
In Firefox I noticed some flickering when dragging a lower item to the top edge of the black box on this page: https://www.dflex.dev/demo/lists/asymmetric/ it might need some debouncing or something since it appears to be repeatedly redordering when it's in right on the edge/border (might not be a standard usecase but it was noticeable).
Demos in the site are behind the current version and not being updated to the latest one [1]. And updating the demos will take a while since I have to take resizing containers into consideration. So the current version is 2.x.x while the last one was 3.7.0. Sorry about that.
It's not the size of the package. DFlex is actually small compared to other libraries. But I need to reconsider the size of the demo container before updating the version because when you resize there's a possibility to add a scroll to the container. Adding/removing scroll while dragging is not shipped yet.
It's true that the HTML drag and drop API is pretty limited for more complex interactions. I recently did a lot of searching for a drag and drop library for a board game I'm working on and almost went with DFlex. I decided to go with DnD Kit because of its powerful React API. However, I'm very glad there's a vanilla JS solution as well with DFlex.
Thanks for the feedback. DnD kit is amazing and the initial library also is so powerful [1]. But we still need a comprehensive solution. Committing changes to DOM with each interaction and shadow caching is not a sustainable solution for building interactive apps. React or any other framework is not designed for interactivity. So even if you are using React you are not actually getting the benefit of React to reconcile because you still committing changes directly to DOM. That's why I built DFlex which has its own reconciler and transformation mechanism.
In the drag-and-drop context, an interactive element is an element that can traverse the DOM tree and change its position without causing a layout shift and with a proper reconciler and transformation mechanism.
HTML drag and drop does have a few powerful features that cannot be done otherwise. You can move an item outside your app into, for example, a native photo library app. Or even on iPhone, drag/drop an item to iMessage and send it to someone as an image or piece of text. Something that also doesn't work in DFlex is scrolling through a page while holding an item, something that also "just works" with native HTML drag and drop.
Sorry for not updating the demo included on the site. But scrolling is working in the newer version. Also, DFlex is not meant for uploading assets to the browser otherwise, it's the future of interactive apps when elements can be transformed and positioned smoothly. This is what I am trying to achieve with DFlex that's why I spent so much time figuring out the optimal solution for reconciling a transformed element instead of adding a layer to html5 and call it a day.
Thanks for sharing the link. Appreciate your feedback. I'd like to point out that the site is not fully updated. The last release is not included in the demo yet but I'm working on it.
As I mentioned in the readme it's a work in progress. But every feature that's shipped is tested with Chrome, Firefox, and Webkit [1]. I'd like to get your feedback though so if you want to open an issue I'll be happy to deal with it.
I hate to ask, since you built this framework with vanilla in mind... but what happens when you use this with React? Does the "infinitely transformed DOM" work with React components and states? Should we not even try?
You are invited to try and give me your feedback or work on any issues you have. The playground and the end-to-end tests are done entirely with React. I am not sure why you suggest it's not going to work with it. Also, it has to be done this way, since how to reconcile transformation is different from than usual reconciler algorithm.
Thank you for the response and sorry about that! I honestly didn't know.
The "Infinite DOM transformation instead of reconstructing the DOM tree with every interaction" bullet, with the "has its own scheduler and reconciler" sentence made it sound like you've purposely implemented your own "lifecycle" system, and I didn't see any mention of React on the readme so I wasn't sure how it'd work together. I don't know what a scheduler or reconciler is, so I wasn't sure what that meant in the context of frameworks. (And edit: And oh, wait, only on a close second reading do I see "compatible with any modern JS framework"... sorry, I ctrl-f'ed the first time).
DFlex has an infinite transformation mechanism even between containers. So you can transform indefinitely and if you want you can enable committing to DOM which will trigger a custom reconciler built specifically for transformation. It's also not just for React, you can hook it with your JS framework.
Yeah that statement is simply not true. Manipulating the DOM was how all of this was done already in the before jQuery days, not to mention many, many libraries since.
Some of the things you think "modern" means, perhaps. What makes it "modern"? On its own, the word conveys nothing useful. It's even worse than something like "fun", which at least implies some kind of commitment to a general mood or vibe, since everyone seems to think their offering is "modern", so you can't really take any meaning from it (the only thing that word on its own really suggests, to me, is "needlessly resource-heavy").
What makes it modern is how it's built and what makes web apps modern today. Its features make it modern, I am not sure why you suggest it's needlessly resource-heavy.
I'm not saying this is resource heavy, I'm saying that it's the only specific thing I can think of that "modern" implies to me (since it's very often true of things that are billed as "modern").
Maybe a better approach would be to consider how you'd try to convey the same information to a reader 50 years in the future, when "modern" may mean something very different to them. What does that actually mean, specifically? What are the good and desirable qualities the term's intended to express to the reader? It's not a good word for communication because it's both vague to begin with, and heavily abused in marketing, so people's ideas of what it might mean vary wildly—it's so lacking in specificity that it may as well be a made-up nonsense word, as far as how much information it carries.
Some things I associate with the word modern:
* New, fallible, and untested
* Trendy and fleeting
* Undocumented
* Incompatible and unsupported
* Needy
* Pet project, single author, no community
I haven't used DFlex or what it intends to replace so I can't comment on what would be a good replacement for the word 'modern', but I doubt you meant to say any of the words I listed above.
Product managers are absolutely ga-ga for drag & drop, no matter how much you tell them it'll at least double the defect rate on the site and slow down all future user-facing feature development. It's that valuable to them, to the tune of effectively hundreds of "story points" over the life of a Web project.
So the use case is adding drag & drop interaction to sites, which is evidently extremely desirable.
I had to build something for my employer's website maybe 12-15 years ago. jQuery was the hot, new thing at the time. So was customizing UI. All available solutions used a combination of absolute positioning & coordinates to determine the interactivity of the elements. As you can imagine, it was a finicky, buggy mess.
I found myself wishing I could just use the DOM's own mouseover event -- but that didn't work, because the cursor was only over the element being dragged. My epiphany was this: When an element was picked up (drag start), I could duplicate every element in the set and set their opacities to zero (I called them "ghosts"). If I gave them a higher z-index than the element being dragged, mouseover events would be triggered on the ghost elements and I wouldn't have to do anything with coordinates, ever. It was also, by far, the most efficient solution at a time when browsers kinda sucked.
(I finally had a reason to share this anecdote.)
Anyway, thanks for this library, I'll be taking a look!