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.

Check out the project here:
Demo
GitHub repo
Installation
Install is the usual one-liner:
pip install streamlit-dnd
Quick start
The whole idea is that you are using normal keyed containers, then call dnd() with their keys after rendering them. Here is a minimal single-list reorder:
import streamlit as st
from streamlit_dnd import dnd, apply_move
if "items" not in st.session_state:
st.session_state.items = {"list": ["Apples", "Bananas", "Cherries", "Dates"]}
# 1. Render a keyed container whose children come from session state
with st.container(key="list", border=True):
for it in st.session_state.items["list"]:
with st.container(key=f"item_{it}", border=True):
st.write(it)
# 2. Turn on drag and drop (call this AFTER rendering the container)
event = dnd("list")
# 3. Apply the drop to session state and rerun
if event:
# You can use the provided utility function apply_move for updating session_state
# OR update session state using the info in the event dictionary yourself
apply_move(event, st.session_state.items)
st.rerun()
That is the entire loop. Render from state, enable dnd, apply the move on a drop. To allow dragging between containers, just pass more keys: dnd("list_a", "list_b").
There are a few options for how it looks and behaves (a border handle by default so buttons and inputs inside your items stay clickable, a “ghost” drop preview, source/destination restrictions for one-way moves, and so on). The README has the full table and a couple of bigger examples.
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.