Skip to content
Open source · MIT · net8.0 / net9.0 / net10.0

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
Board.razor
<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!);
Write the docs
Review the PR
Ship the release
Drop a card to archive it
React DnD's modelitems, types, monitors and drop results
Drag state in C#the browser layer only does what C# cannot
Native OS dragsfiles, text, links and HTML
Every hosting modelWebAssembly, Server, Web App and Hybrid

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.

Single target →

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.

Chessboard tutorial →

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.

Custom drag layer →

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.

Sortable →

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.

Nested drop targets →

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.

Native files →

In practice

See it in code

01

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.

Getting started →
builder.Services.AddBitBdndServices();   // Program.cs

<BdndProvider>
    …draggables and drop targets…
</BdndProvider>
02

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>
03

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.

Copy or move →
<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.

ConcernReact DnDBit.Bdnd
The context<DndProvider backend={HTML5Backend}><BdndProvider>, the HTML5 backend built in
A drag sourceuseDrag({ type, item })<BdndDraggable Type Item>
A drop targetuseDrop({ accept, drop })<BdndDropTarget Accept OnDrop>
Only the innermost targetisOver({ shallow: true })IsOverShallow
Your own previewgetEmptyImage() and useDragLayerUseCustomDragLayer and <BdndDragLayer>
Files from the desktopNativeTypes.FILE in dropBdndNativeTypes.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.

Try the MCP server →

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
An unhandled error has occurred. Reload 🗙