Drag and drop for Blazor,
the React DnD way.
Declare what can be dragged and where it can go - BdndDraggable,
BdndDropTarget, BdndDragLayer, BdndDragHandle - and render
from the state they hand you. Typed items matched by type, custom drag previews, handles, nesting
and native file drops, on the browser's own HTML5 drag and drop, with the drag state in C#.
dotnet add package Bit.Bdnd
<BdndDraggable TItem="Card" Type="card" Item="card"> … </BdndDraggable> <BdndDropTarget TItem="Card" Accept="card" OnDrop="Archive"> … </BdndDropTarget> private void Archive(BdndDropEventArgs<Card> e) => _cards.Remove(e.Item!);
Capabilities
Everything React DnD does - as Blazor components
Where React DnD has hooks, Bdnd has components: a draggable, a drop target, a drag layer and a drag handle, each handing its child content the state to render from. The demo ports React DnD's own examples, so every one of them can be opened side by side.
Sources and targets
BdndDraggable is useDrag and BdndDropTarget is
useDrop: Type and Item on one, Accept and
OnDrop on the other, and IsDragging, IsOver and
CanDrop to render from.
Typed items, gated drops
Any C# object is an item, matched by its type string. CanDropPredicate narrows a
target further from the item itself - a chessboard square takes only a legal knight move.
Custom previews and handles
UseCustomDragLayer hides the browser's ghost and a BdndDragLayer draws
your own from the live offsets; UseHandle starts a drag only from a
BdndDragHandle.
Sortable lists
Cards that are each a draggable and a drop target, reordered from OnHover as the
dragged card passes their middle - React DnD's algorithm, without the flicker.
Nesting
Nested sources drag the innermost one; nested targets report IsOver for every
target under the pointer and IsOverShallow for the innermost, and drops reach them
innermost first.
Native drags
Accept files from the desktop, and text, links and HTML from any page, with
BdndNativeTypes - read in OnNativeDrop while the browser still lets
them be read.
In practice
See it in code
Wrap a region in a provider
One service registration, then a BdndProvider around whatever drags and drops.
Each provider creates the manager its components share - there is nothing to configure.
builder.Services.AddBitBdndServices(); // Program.cs <BdndProvider> …draggables and drop targets… </BdndProvider>
Declare a source and a target
A draggable carries an item of a type; a target accepts the types it lists. Both hand their content the collected state, so the hover and the dragging look are one expression each.
Multiple targets →<BdndDraggable TItem="Box" Type="box" Item="box" Context="drag"> <div style="opacity: @(drag.IsDragging ? 0.4 : 1)">@box.Name</div> </BdndDraggable> <BdndDropTarget TItem="Box" AcceptTypes="@(["box", "crate"])" OnDrop="Store" Context="drop"> <div class="bin @(drop.CanDrop ? "ready" : "")">Drop here</div> </BdndDropTarget>
Read the outcome
A target can publish a result from OnDrop; the source's OnEnd
receives it with DidDrop, which tells a drop from a cancel - and runs even if
the drop re-rendered the source away.
<BdndDraggable TItem="Box" Type="box" Item="box" OnEnd="Ended">…</BdndDraggable> private void Ended(BdndDragEndContext<Box> e) { if (e.DidDrop) _palette.Remove(e.Item!); // e.DropResult: what the target set }
Comparison
Coming from React DnD?
The same concepts under the names a Blazor component gives them. There are no connector refs to attach - a component's host element is the source or the target - and native drops have a callback of their own.
| Concern | React DnD | Bit.Bdnd |
|---|---|---|
| The context | <DndProvider backend={HTML5Backend}> | <BdndProvider>, the HTML5 backend built in |
| A drag source | useDrag({ type, item }) | <BdndDraggable Type Item> |
| A drop target | useDrop({ accept, drop }) | <BdndDropTarget Accept OnDrop> |
| Only the innermost target | isOver({ shallow: true }) | IsOverShallow |
| Your own preview | getEmptyImage() and useDragLayer | UseCustomDragLayer and <BdndDragLayer> |
| Files from the desktop | NativeTypes.FILE in drop | BdndNativeTypes.File in OnNativeDrop |
Where to start
Choose your path
New to Bdnd?
Install, register one service, wrap a region in a provider - a first drop in five minutes.
Getting started →Coming from React DnD?
Its examples are ported one for one - start with the chessboard tutorial you already know.
Open the tutorial →Building with an AI agent?
This site is an MCP server: point your agent at /mcp and it reads the shipped library instead of guessing.
Questions
Frequently asked
Is this React DnD running through JavaScript interop?
No. The drag state - the item, its type, the source, the offsets, every target's hover and the
drop result - lives in a C# manager shared by the components of a BdndProvider. A
small script module does only what C# cannot: configure the native drag while
dragstart is being dispatched, follow the pointer, track hover and read native drops.
Which render modes does it work in?
Any interactive one, on .NET 8, 9 and 10: WebAssembly is the best fit, since every
dragover is handled without a network round trip; Server, Auto and Hybrid work the
same, a round trip later. Prerendered markup shows the idle state and starts working once the
page is interactive.
Does it work on touch screens?
Like React DnD's HTML5 backend, Bdnd has no touch backend: it needs a pointer that raises HTML5 drag events - a mouse, a pen or a trackpad.
Can I read the contents of a dropped file?
During a drop the browser exposes only a file's name, size and MIME type, and that is what
OnNativeDrop receives. To read the contents, use an InputFile - an
invisible one layered over the drop zone, for instance - or your own interop.
Is there a stylesheet to include?
No. Bdnd draws nothing of its own - what is dragged and where it lands look the way your markup says - and its script module is imported by the components the first time they need it.
Pick it up, put it down
One package, one service, one provider - and any part of a page drags and drops.
dotnet add package Bit.Bdnd