I build a custom component that adds drag and drop behavior to the contents of a container

Hey everyone,

I am excited to share a new custom component I have been working on: streamlit-dnd which makes things inside your Streamlit containers drag and droppable. You make sure the container(s) you want to target are each given a key and then pass the key(s) to the dnd function and the direct children of those containers become draggable. You can reorder items inside a single container, or drag them between containers. When a drop happens, you get an event dictionary back with info describing the move so you can update your session_state which you can then use to update the app so that the app reflects the change.

streamlit-dnd-demo

Check out the project here:

Demo

GitHub repo

Background

Some of you might remember a post I made almost two years ago about a proof of concept for draggable Streamlit containers. That one got a lot of interest, and I always meant to turn it into something you could actually install and use. But I kept hitting roadblocks in two areas.

The first was due to me trying to code the drag-and-drop behavior completely from scratch, and I did not have much experience coding the inner workings of dnd. The second stumbling block was Streamlit itself. Over time, updates changed the layout structure of containers enough that the way I was targeting elements to attach dnd behavior stopped working. Between those two things, the proof of concept stayed a proof of concept.

What finally got me past both walls was using AI to fill in the gaps in my knowledge, specifically the dnd internals I was weak on. I want to be clear that this is not a vibe coded project. I had a direct hand in solving the crucial problems. I provided the targeting approach for finding and hooking into the right container elements, and the logic for making this play nicely with how Streamlit actually works. A good example of the latter: the component does not force a rerun on every drag event. It reports the drop event back to you and leaves how the app should respond/change up to you, because that is the level of control I would want for this type of component. That was a deliberate design call based on my experience building streamlit apps and custom components.

I mostly relied on AI for the dnd plumbing and some code organization. And just to underline the point: I did attempt to one-shot the whole thing with AI (no code) using multiple Opus and Codex models and failed to get it working.

Truth be told, the delay in finishing this is also due to me focusing on other major projects such as PyNote which is based off of prototypes I build using Streamlit and has dnd container behavior…


If you find this interesting or useful, please give it a try, and let me know if you build anything with it (ill be glad to give stars and recs etc). Issues and PRs welcome on GitHub.

The component looks absolutely great! I’m sure it’ll be handy in many different cases.

Honorable mention for the tracks you chose for the “Playlist” use case: unique rock masterpieces :guitar:

Thanks!

Actually, since the post, I have added a few more features. You can now pass a list of keys to exclude items/streamlit components from dnd functionality (prevent them from being draggable). I also enabled touch dragging for mobile devices. And finally, I added a placeholder text argument for adding placeholder text when there are no items in the dnd container(s). You can see these in action in the demo which has been updated as well!